I'm studying golang and I'm a little confused about defining methods on values or pointers. As mentioned in the doc:
Next is consistency. If some of the methods of the type must have pointer receivers, the rest should too, so the method set is consistent regardless of how the type is used. See the section on method sets for details.
If I have a type T, it need to implement several interfaces. One interface has method which need to use pointer receiver, and methods in another interfaces can work pretty well with value receiver. Is it necessary to change all methods in all interfaces to have pointer receivers? If so, why?
It depends :)
Your type T has two method sets:
method set of receiver (t T) which is all methods defined with receiver (t T)
method set of receiver (t *T) which is all methods that have receiver (t *T) AND all methods that have receiver (t T)
So if you have an interface that is satisfied by T, it is also satisfied by *T. (but not vice versa)
Hence, if you have to add a *T receiver method to a type to satisfy an interface you do not need to change the other method receivers to *T, but you will have to be aware that now only a *T satisfies that interface and not a T and other interfaces may be satisfied for both.
type fooer interface {
foo()
}
type barer interface {
bar()
}
type T struct {}
func (t T)foo(){}
func (t *T)bar(){}
var _ fooer = T{} // ok
var _ barer = T{} // NOT OK - won't compile
var _ barer = &T{} // ok
var _ fooer = &T{} // ok
Confusing? Yes it can be. So although you don't have to change all of the methods to have a pointer receiver it's more consistent and less confusing if you do - that way you know that you are always dealing with a *T in your code - and it seems to be what most people do.
It is not needed. What you cited is just an argument for doing so. It is therefore recommended.
As you have mentioned about Golang spec for methods have pointer or value receiver. If an interface as a method receiver then its better for consistency to have other methods with pointer receivers
. But It is not necessary.
Lets take a requirement of pointer receivers. Suppose I have a struct which contains details of DB connection and session. And there are methods which are using same connection for methods with insert/update/delete queries. Then it is better to pointer receiver so that you need not to create connection every time. You can manage with current session for all methods used to query database.
type Env struct {
db *sql.DB
}
func main() {
db, err := models.NewDB("postgres://user:pass@localhost/dbname")
if err != nil {
log.Panic(err)
}
env := &Env{db: db}
}
func (env *Env) fetch(){}
func (env *Env) Insert(){}
func (env *Env) Update(){}