Consider a binary tree node:
type Node struct {
value uint8
left, right *Node
}
If I want to add a function to each Node, should it be:
A: func (n *Node) height() int
or
B: func (n Node) height() int
I want to know which of A or B you would choose and why.
I can model linked lists or recursive structs, but I don't know when the receiver should be a pointer or not-a-pointer.
The main difference is the idea of pass by value
vs pass by reference
When you're using example A you're passing be reference, meaning that any changes you apply to n
inside of func (n *Node) height
will apply to the Node you're using to call Node.height()
.
By comparison, what you're doing in example B is passing by value where you're really just passing a copy of the Node you're using to call Node.height()
so any changes to that Node will not apply outside of the function.
Here is a small playground to demonstrate the differences: http://play.golang.org/p/JodPRPBHDg
Notice in the example that when you call node.incHeight()
, it goes to the function:
func (n Node) incHeight() uint8 {
n.value++
return n.value
}
Because this is pass by value the node.value
is still the same unless you store the returned value as node.value
. However, if you call node.incrementHeight()
it goes to the function:
func (n *Node) incrementHeight() {
n.value++
return
}
This will change the value of node.value
without needing to return anything because its referencing the original struct, rather than a copy of the struct.
So in answer to which would you choose and why, it really depends on whether you want to be able to make lasting changes to the struct you're using to call the function or if you'd rather just pass a copy that can see and alter the values but only while within the function and not have any lasting effects on the original struct.
There is a very nice explanation in https://code.google.com/p/go-wiki/wiki/Style
Receiver Type
Choosing whether to use a value or pointer receiver on methods can be difficult, especially to new Go programmers. If in doubt, use a pointer, but there are times when a value receiver makes sense, usually for reasons of efficiency, such as for small unchanging structs or values of basic type. Some rules of thumb:
If the receiver is a map, func or chan, don't use a pointer to it.
If the receiver is a slice and the method doesn't reslice or reallocate the slice, don't use a pointer to it.
If the method needs to mutate the receiver, the receiver must be a pointer.
If the receiver is a struct that contains a sync.Mutex or similar synchronizing field, the receiver must be a pointer to avoid copying.
If the receiver is a large struct or array, a pointer receiver is more efficient. How large is large? Assume it's equivalent to passing all its elements as arguments to the method. If that feels too large, it's also too large for the receiver.
Can function or methods, either concurrently or when called from this method, be mutating the receiver? A value type creates a copy of the receiver when the method is invoked, so outside updates will not be applied to this receiver. If changes must be visible in the original receiver, the receiver must be a pointer.
If the receiver is a struct, array or slice and any of its elements is a pointer to something that might be mutating, prefer a pointer
receiver, as it will make the intention more clear to the reader.If the receiver is a small array or struct that is naturally a value type (for instance, something like the time.Time type), with no mutable fields and no pointers, or is just a simple basic type such as int or string, a value receiver makes sense. A value receiver can reduce the amount of garbage that can be generated; if a value is passed to a value method, an on-stack copy can be used instead of allocating on the heap. (The compiler tries to be smart about avoiding this allocation, but it can't always succeed.) Don't choose a value receiver type for this reason without profiling first.
Finally, when in doubt, use a pointer receiver.