Why can't I assign type's value to an interface implementing methods with receiver type pointer to that type?

前端 未结 4 1832
借酒劲吻你
借酒劲吻你 2021-02-08 19:53

I am 2-days old in the world of Golang, and going through the go tour. I couldn\'t help but notice a peculiarity which I cannot seem to be able to come at terms with a

相关标签:
4条回答
  • 2021-02-08 20:26

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

    *Vertex is a type. It’s the “pointer to a Vertex” type. It’s a distinct type from (non-pointer) Vertex. The part about it being a pointer is part of its type.

    You need consistency of type.

    "Methods, Interfaces and Embedded Types in Go":

    The rules for determining interface compliance are based on the receiver for those methods and how the interface call is being made.
    Here are the rules in the spec for how the compiler determines if the value or pointer for our type implements the interface:

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

    This rule is stating that if the interface variable we are using to call a particular interface method contains a pointer, then methods with receivers based on both values and pointers will satisfy the interface.

    • The method set of any other type T consists of all methods with receiver type T.

    This rule is stating that if the interface variable we are using to call a particular interface method contains a value, then only methods with receivers based on values will satisfy the interface.

    Karrot Kake's answer about method set is detailed also in go wiki:

    The method set of an interface type is its interface.

    The concrete value stored in an interface is not addressable, in the same way that a map element is not addressable.
    Therefore, when you call a method on an interface, it must either have an identical receiver type or it must be directly discernible from the concrete type.

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

    ("has no address" means actually that it is not addressable)

    0 讨论(0)
  • 2021-02-08 20:26

    nice Question.
    this is Golang type system: the Vertex and *Vertex are different types,
    see this clarifying sample:
    you can use type Vertex2 Vertex to define new Vertex2 type and these are different types too:

    while this is working:

    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(v.X*v.X + v.Y*v.Y)
    }
    
    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(v.X*v.X + v.Y*v.Y)
    }
    
    type Vertex struct {
        X, Y float64
    }
    type Abser interface {
        Abs() float64
    }
    

    the error is:

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

    exactly 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(v.X*v.X + v.Y*v.Y)
    }
    
    type Vertex struct {
        X, Y float64
    }
    type Abser interface {
        Abs() float64
    }
    

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

    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(v.X*v.X + v.Y*v.Y)
    }
    
    type Vertex struct {
        X, Y float64
    }
    type Abser interface {
        Abs() float64
    }
    

    output:

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

    because:
    A type may have a method set 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 also contains the method set of T). Further rules apply to structs containing anonymous fields, as described in the section on struct types. Any other type has an empty method set. In a method set, each method must have a unique non-blank method name.

    The method set of a type determines the interfaces that the type implements and the methods that can be called using a receiver of that type.
    ref: https://golang.org/ref/spec#Method_sets

    0 讨论(0)
  • Values stored in an interface are not addressable - but why? See here for the answer.

    tl;dr its because a pointer to A which points to a value of type A in an interface would be invalidated when a value of different type B is subsequently stored in the interface.

    0 讨论(0)
  • 2021-02-08 20:28

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

    0 讨论(0)
提交回复
热议问题