Structs & Methods
Structs and methods in Go — declaring structs, methods, value vs pointer receivers, embedding as composition, and the constructor idiom.
8 questions
JuniorTheoryVery commonWhat is a struct in Go?
What is a struct in Go?
A struct is a composite type that groups named fields, each with its own type. It is a value type: assigning or passing it copies every field. Structs support embedding (composition), methods, and field tags. Its zero value has each field at that field's own zero value, and two structs are comparable with == when all their fields are comparable.
Common mistakes
- ✗Thinking a struct is a reference type — assigning or passing it copies every field
- ✗Believing a struct cannot have methods or embed other types
- ✗Assuming every struct is comparable with
==regardless of its field types
Follow-up questions
- →How does embedding differ from inheritance in other languages?
- →Which field types make a struct non-comparable, and why?
JuniorTheoryCommonHow does Go initialize a struct without constructors?
How does Go initialize a struct without constructors?
Go has no constructors. The idiom is a plain factory function, conventionally NewT(...), that takes the inputs, validates them, and returns an initialized *T or T. It is an ordinary function, not special syntax — nothing forces callers to use it. Often the struct's zero value is already usable, so no constructor is needed at all; you write NewT only when construction must validate inputs or set up non-zero defaults.
Common mistakes
- ✗Believing Go runs a
New/Initconstructor method automatically - ✗Thinking the zero value is never usable and always needs a factory
- ✗Assuming callers are forced to use
NewTrather than a plain literal
Follow-up questions
- →When is a struct's zero value usable enough to skip a constructor?
- →Why return
*Trather thanTfrom aNewTfactory function?
JuniorTheoryCommonWhat does the program print?
What does the program print?
1 9
Open full question →Common mistakes
- ✗Expecting
qto change too:q := pcopies every field of the struct, soqis a separatePointthat keepsXequal to1. - ✗Expecting
r.X = 9to need(*r).X: Go dereferences a pointer to a struct for you, sor.Xwrites the field ofpitself.
Follow-up questions
- →What would
fmt.Println(r.X)print at the end of the program? - →How would you pass a
Pointto a function so that the function can change it?
JuniorTheoryCommonWhat does the program print?
What does the program print?
dog pet
Open full question →Common mistakes
- ✗Expecting
dog dog:Sayis a method ofAnimal, so itsa.Kind()callsAnimal.Kind; embedding is not inheritance, andDog's method is never reached. - ✗Expecting
pet petor a compile error:Dog's ownKindshadows the promoted one, soDog{}.Kind()calls it without any conflict.
Follow-up questions
- →How do you still reach an embedded field after an own field shadows it?
- →If two embedded types promote the same method name, what happens?
JuniorTheoryCommonWhat does the program print?
What does the program print?
6 5
Open full question →Common mistakes
- ✗Expecting a compile error: a method's name belongs to its type, so the method
Rect.Areaand the functionAreado not clash. - ✗Expecting both calls to reach one function:
r.Area()calls the method withras its receiver, andArea(2, 3)the plain function.
Follow-up questions
- →Why must a method's receiver type be defined in the same package?
- →How does the receiver let you call a method as
c.Inc()instead ofInc(c)?
JuniorTheoryCommonWhat does the program print?
What does the program print?
1 1
Open full question →Common mistakes
- ✗Expecting
1 2: a value receiver gets a copy ofcon every call, so each call raises its own copy from0to1andc.nstays0. - ✗Expecting a value receiver to be read-only: the method may change its copy freely, and
return c.nreturns that changed copy's1.
Follow-up questions
- →What does the program print if
Incgets the pointer receiver(c *Counter)? - →What is the value of
c.nafter the two calls in this program?
MiddleTheoryCommonWhen should a method use a pointer receiver instead of a value receiver?
When should a method use a pointer receiver instead of a value receiver?
Use a pointer receiver when the method must mutate the receiver, since a value receiver only gets a copy and the change is lost. Use one too when the struct is large, to avoid copying every field on each call, or for consistency when some methods on the type already need a pointer — mixing receiver kinds is discouraged. A value receiver fits small, immutable types where a copy is cheap and safe, and it also leaves the value usable concurrently.
Common mistakes
- ✗Using a value receiver for a method that must mutate the receiver
- ✗Copying a large struct on every call instead of taking a pointer
- ✗Mixing value and pointer receivers inconsistently across one type
Follow-up questions
- →Why is mixing pointer and value receivers on one type discouraged?
- →How does the receiver choice affect which method set satisfies an interface?
JuniorCodeOccasionalWhy does this method's mutation not persist, and how do you fix it?
Why does this method's mutation not persist, and how do you fix it?
It prints foo. A method call is sugar for passing the receiver as an argument, and Set has a value receiver, so b is a copy — b.Value = s mutates the copy and the original is untouched. Even passing &bs would still print foo, because Set copies the value regardless. Fix: make Set a pointer receiver, func (b *BasicStruct) Set(s string), and pass &bs.
Common mistakes
- ✗Thinking a value receiver mutates the caller's struct rather than a copy
- ✗Believing passing
&bsalone fixes it without changing the receiver - ✗Assuming the code fails to compile rather than just printing the unchanged value
Follow-up questions
- →Why is a value-receiver method in the method set of both
Tand*T? - →After switching
Setto a pointer receiver, why must you pass&bsnotbs?