Assuming we have an understanding that,
For explicit method definition for type
X
, GO compiler implicitly defines the same method for type*X
and vice versa , if I declare,func (c Cat) foo(){ //do stuff_ }
and declare,
func (c *Cat) foo(){ // do stuff_ }
then GO compiler gives error,
Compile error: method re-declared
which indicates that, pointer method is implicitly defined and vice versa
In the below code,
package main
type X interface{
foo();
bar();
}
type Cat struct{
}
func (c Cat) foo(){
// do stuff_
}
func (c *Cat) bar(){
// do stuff_
}
func main() {
var c Cat
var p *Cat
var x X
x = p // OK; *Cat has explicit method bar() and implicit method foo()
x = c //compile error: Cat has explicit method foo() and implicit method bar()
}
GO compiler gives error,
cannot use c (type Cat) as type X in assignment:
Cat does not implement X (bar method has pointer receiver)
at x = c
, because, implicit pointer methods satisfy interfaces, but implicit non-pointer methods do not.
Question:
Why implicit non-pointer methods do not satisfy interfaces?
Let's look into the language specification :
A type may have a associated with it. 。 The method set of an interface type is its interface. The method set of any other type T consists of all methods declared with receiver type T. The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it of T). T)。
In your example, the method set of the interface type x
is [foo(), bar()]
. The method set of the type Cat
is [foo()]
, and the method set of the type *Cat
is [foo()]
+ [bar()]
= [foo(), bar()]
.
This explains, why variable p
satisfies the interface x
, but variable c
doesn't.
How about this?
package main
import (
"fmt"
)
type Growler interface{
Growl() bool
}
type Cat struct{
Name string
Age int
}
// *Cat is good for both objects and "references" (pointers to objects)
func (c *Cat) Speak() bool{
fmt.Println("Meow!")
return true
}
func (c *Cat) Growl() bool{
fmt.Println("Grrr!")
return true
}
func main() {
var felix Cat // is not a pointer
felix.Speak() // works :-)
felix.Growl() // works :-)
var ginger *Cat = new(Cat)
ginger.Speak() // works :-)
ginger.Growl() // works :-)
}
Following the spec :
The method set of any other named type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T).
Method set definition sounds weird until you follow addressable and not addressable types concept.
It is possible to call a pointer receiver method on a value if the value is of addressable type.
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv.
As with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.
It is ok to call pointer receiver methods on values till you are dealing with addressable types (struct is addressable):
type Cat struct {}
func (c *Cat) bar() string { return "Mew" }
func main() {
var c Cat
c.bar()
}
But not all Go types are addressable. Also variables referenced through interfaces are not addressable .
It is impossible to call pointer receiver on values of not addressable types:
type X interface {
bar() string
}
type Cat struct{}
func (c *Cat) bar() string { return "Mew" }
/* Note `cat` variable is not a `struct` type value but
it is type of `X` interface therefor it is not addressable. */
func CatBar(cat X) {
fmt.Print(cat.bar())
}
func main() {
var c Cat
CatBar(c)
}
So with the following error Go runtime prevents segment fault:
cannot use c (type Cat) as type X in assignment: Cat does not implement X (bar method has pointer receiver)
Add a little to dev.bmax's answer.
type Cat struct{
}
func (c Cat) foo(){
// do stuff_
}
func (c *Cat) bar(){
// do stuff_
}
you can do
var c cat
c.bar() // ok to call bar(), since c is a variable.
but not
cat{}.bar() // not ok to call bar(), c is not a variable.
It's legal to call a *T method on an argument of type T so long as the argument is a variable ; the compiler implicitly takes its address. But this is mere syntactic sugar: a value of type T does not posses all methods that a *T pointer does, and as a result it might satisfy fewer interfaces.
On the other hand, you can always call foo() with Cat or *Cat.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.