Interfaces in Go are pretty interesting. They're declared as a set of methods that a type -- any type -- must implement to satisfy the interface.
Types in Go don't state their compliance -- or intention to comply -- with an interface like classes do in other languages like Java. They either do or do not satisfy the interface by supporting the methods.
Methods in Go can have a struct receiver or a pointer receiver. For example, given a Person
struct:
type Person struct {
name string
}
You could implement a Hello()
method as either
func (p Person) Hello() string {
return "Hello " + p.name
}
or
func (p *Person) Hello() string {
return "Hello " + p.name
}
The difference between the two is what p
is: in the case of the former, p
is a copy of the Person
struct, and any changes you make won't be reflected in the caller.
In the case of the latter -- where p
is a pointer receiver, *Person
-- p
is mutable, and its contents can be changed. Another difference is that when you use a pointer receiver the contents of p
don't need to be copied before executing the Hello()
method. This can be really important for large structs.
The fact that you don't have to explicitly declare that you implement an interface means they're easy to treat as emergent behavior: as you realize you need two different kinds of People
, you declare an interface, Individual
.
type Individual interface {
Hello() string
}
Something that's bitten me a few times -- although I'm slowly internalizing it -- is the fact that while *Person
is a pointer to a Person
struct, *Individual
is not a pointer to "any type implementing Individual".
*Individual
is a pointer to the interface itself.
A parameter that's an interface type doesn't tell you anything about whether it's a pointer or a copy. Either can implement the interface, depending on how the methods are declared.