Why can't I assign a value to a type to an interface that implements methods with a pointer of a receiver type to this type?

I am 2 days in the world of Golang, and I am going on a tour. I could not help but notice a special feature, which, apparently, cannot come to an agreement with the right reasoning.

This code works fine:

package main import ( "fmt" "math" ) type Vertex struct{ X,Y float64 } type Abser interface{ Abs() float64 } func (v Vertex) Abs() float64{ //method with value receiver argument return math.Sqrt(vX*v.X+vY*vY) } func main(){ var myVer Vertex = Vertex{3,4} var inter Abser inter = &myVer //assigning *Vertex type to inter fmt.Println(inter.Abs()) } 

Meanwhile, the following code shows an error:

 package main import ( "fmt" "math" ) type Vertex struct{ X,Y float64 } type Abser interface{ Abs() float64 } func (v *Vertex) Abs() float64{ //method with pointer receiver argument return math.Sqrt(vX*v.X+vY*vY) } func main(){ var myVer Vertex = Vertex{3,4} var inter Abser inter = myVer //assigning Vertex type to inter fmt.Println(inter.Abs()) } 

Mistake:

interface.go: 18: cannot use myVer (Vertex type) as Abser type in assignment: Vertex does not implement Abser (Abs method has a pointer receiver)

Until you got to this section of the tour, I realized that the creators of Go let go of bulky designations like

(* v) .method1name ()

(& v) .method2name ()

Thus, methods with value receivers can be used with both values ​​and pointers and vice versa.

Why does a language work between two (value and pointer) when working with interfaces? Wouldn't it be more convenient if the same reference / dereferencing principles apply here?

I hope that I do not miss something too obvious. Thanks!

+7
go
source share
4 answers

" Intro ++ to Go Interfaces " illustrates the problem:

*Vertex is a type. Its a "pointer to type Vertex ." Its a distinct type from (not a pointer) Vertex . The part that this is a pointer is part of its type.

You need type consistency.

" Methods, Interfaces, and Built-in Types in Go ":

The rules for determining the correspondence of an interface are based on the receiver for these methods and methods of invoking the interface.
Here are the rules in the specification for how the compiler determines whether a value or pointer implements an interface for our type :

  • The set of methods of the corresponding pointer type *T is the set of all methods with a receiver *T or T

This rule states that if the interface variable that we use to call a specific interface method contains a pointer, then methods with receivers based on both values ​​and pointers will satisfy the interface.

  • A collection of methods of any other type T consists of all methods with a receiver type T

This rule states that if an interface variable that we use to call a specific interface method contains a value, then only methods with receivers based on values ​​will satisfy the interface.

Karrot Kake answer about described in detail in the go wiki :

A set of methods such as an interface is its interface.

The specific value stored in the interface is not addressed , just as the map element is not addressed.
Therefore, when you call a method on an interface, it must either have an identical receiver type, or it must be directly distinguishable with a specific type.

Pointer methods and receiver values ​​can be called with pointers and values ​​respectively, as you would expect.
The receiver-receiver method can be called with indicative values, because they can be dereferenced first .
The destination pointer methods cannot be called with values ​​because the value stored inside the interface has no address .

("has no address" means that it is not addressed )

+4
source share

The set method for the pointer type includes methods for the receiver of the value , but the method set for the value does not include methods for the receiver of the pointer. The method specified for the value type does not include pointer receiver methods, because the values ​​stored in the interface are not addressable .

+3
source share

good question.
this is a system like Golan: Vertex and *Vertex are different types ,
see this illustrative example:
you can use type Vertex2 Vertex to define a new type of Vertex2 , and these are also different types:

while it works:

 package main import "fmt" import "math" func main() { var myVer Vertex = Vertex{3, 4} var inter Abser = myVer //assigning Vertex type to inter fmt.Println(inter.Abs()) } func (v Vertex) Abs() float64 { //method with pointer receiver argument return math.Sqrt(vX*vX + vY*vY) } type Vertex struct { X, Y float64 } type Abser interface { Abs() float64 } 

this will not work:

 package main import "fmt" import "math" func main() { var myVer Vertex = Vertex{3, 4} var inter Abser = myVer //assigning Vertex type to inter fmt.Println(inter.Abs()) } type Vertex2 Vertex func (v Vertex2) Abs() float64 { //method with pointer receiver argument return math.Sqrt(vX*vX + vY*vY) } type Vertex struct { X, Y float64 } type Abser interface { Abs() float64 } 

mistake:

. \ m.go: 8: cannot use myVer (Vertex type) as Abser type in destination:
Vertex does not implement Abser (Abs method is missing)

exactly the same error with your sample:

 package main import "fmt" import "math" func main() { var myVer Vertex = Vertex{3, 4} var inter Abser = myVer //assigning Vertex type to inter fmt.Println(inter.Abs()) } func (v *Vertex) Abs() float64 { //method with pointer receiver argument return math.Sqrt(vX*vX + vY*vY) } type Vertex struct { X, Y float64 } type Abser interface { Abs() float64 } 

because the two Vertex and Vertex2 are different types.
and this also works :

 package main import "fmt" import "math" func main() { var inter Abser = &Vertex{3, 4} //assigning &Vertex type to inter fmt.Printf("inter: %#[1]v\n", inter) fmt.Println(inter.Abs()) } func (v Vertex) Abs() float64 { //method with pointer receiver argument return math.Sqrt(vX*vX + vY*vY) } type Vertex struct { X, Y float64 } type Abser interface { Abs() float64 } 

output:

 inter: &main.Vertex{X:3, Y:4} 5 

because:
A type can have a set of methods associated with it. A set of methods such as an interface is its interface. A collection of methods of any other type T consists of all methods declared with a receiver type T. A collection of methods of the corresponding pointer type * T is a collection of all methods declared with a receiver * T or T (that is, it also contains a collection of methods T) . Additional rules apply to structures containing anonymous fields, as described in the section on structure types. Any other type has an empty set of methods. In a set of methods, each method must have a unique name for a non-empty method.

A set of type methods defines the interfaces that the type implements and the methods that can be invoked using a receiver of this type.
ref: https://golang.org/ref/spec#Method_sets

+2
source share

The values ​​stored in the interface are not addressable - but why? See here for an answer.

tl; dr , because a pointer to A that points to a value of type A in the interface will be invalid when a value of another type B is subsequently stored.

0
source share

All Articles