Methods
There are no classes in Go. But, we can define methods on types.
A method is a function with special receiver argument. The receiver appears in its own argument list between the func
keyword and the method name.
Example (Method)
Note that methods are still functions, just with a receiver argument.
Example (Regular Function)
Methods on Non-Struct Types
We can declare a method on non-struct types, too.
In this example we see a numeric type MyFloat
with an Abs
method.
You can only declare a method with a receiver whose type is defined in the same package as the method. You cannot declare a method with a receiver whose type is defined in another package (which includes the built-in types such as int
).
Here we see a numeric type MyFloat
with an Abs
method.
Pointer Receivers
We can declare methods with pointer receivers. The receiver type has *T
for some type T
(Note that T
cannot be a pointer itself, say *int
)
Example 1 (Pointer Receiver)
Methods with pointer receivers can modify the value to which the receiver points (as Scale
does here). Since methods often need to modify their receiver, pointer receivers are more common than value receivers.
Example 2 (Value Receiver)
We only removed the *
from the function declaration of scale
. Notice we do not need to change v.Scale(10)
on line 23 to (&v).Scale(10)
. Keep reading :)
Now, with a value receiver, the original Vertex
value is not changed. This is because the Scale
method operates on a copy of the original Vertex
value. (This is the same behavior as for any other function argument.) The Scale
method must have a pointer receiver to change the Vertex
value declared in the main
function.
Example 3 (Function Version)
Here are the Abs
and Scale
methods rewritten as functions. If we change this to passing by value (instead of reference) by just removing the *
from line 16, the code would not compile:
We also need to change &v
to v
. And the output is:
Methods and Pointer Indirection 1
The previous examples lead us to some differences the pointer and value receivers in actual code writing.
Example 4
In this example, for the function version, the function with a pointer argument must take a pointer.
However, for the method version, the method with pointer receivers take either a value of a pointer as the receiver when they are called:
For the statement v.Scale(5)
, even though v
is a value and not a pointer, the method with the pointer receiver is called automatically. That is, as a convenience, Go interprets the statement v.Scale(5)
as (&v).Scale(5)
since the Scale
method has a pointer receiver. (&v).Scale(5)
still works certainly!
Methods and Pointer Indirection 2
Conversely, we have the same thing.
Example
For functions that take a value argument, they must take a value of that specific type.
For methods with value receivers, they take either a value or a pointer as the receiver when they are called:
Similarly, p.Abs()
is interpreted as (*p).Abs()
by Go.
Choosing a Value or Pointer Receiver
Two main reasons:
To modify the value that its receiver points to
To avoid copying the values on each method call. For example, if the receiver is a large struct, this can be efficient.
In general, all methods on a given type should have either value or pointer receivers, but not a mixture of both. (introduced later)
Last updated