dongxi7704
2017-01-29 14:49
浏览 25
已采纳

为什么隐式非指针方法不能满足接口?

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?

图片转代码服务由CSDN问答提供 功能建议

假设我们已经了解,

对于 如果明确声明了 X 类型的方法定义,则GO编译器会隐式定义 * X 类型和反之亦然相同的方法, >

  func(c Cat)foo(){
 //执行stuff_ 
} 
   
 
 

并声明,< / p>

  func(c * Cat)foo(){
 //做stuff_ 
} 
   
 
 

然后 GO编译器给出错误,

 编译错误:方法重新声明
   
 
 

,这表明指针方法是 隐式定义,反之亦然


在以下代码中, < pre> package main type X interface { foo(); bar(); } type Cat struct { } func(c Cat)foo (){ //做stuff_ } func(c * Cat)bar(){ //做stuff_ } func main(){ var c Cat var p *猫 var x X x = p //确定; * Cat具有显式方法bar()和隐式方法foo() x = c //编译错误:Cat具有显式方法foo()和隐式方法bar() }


GO编译器出错,

 不能在分配中使用c(类型Cat)作为X类型:
 Cat 不实现X(bar方法具有指针接收器)
   
 
 

x = c 处,因为隐式指针方法满足接口,但是隐式 非指针方法不。

问题:

为什么隐式非指针方法不满足接口?

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

4条回答 默认 最新

  • doubei3312 2017-01-29 15:28
    已采纳

    Let's look into the language specification:

    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).

    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.

    已采纳该答案
    打赏 评论
  • doutangliang7769 2017-01-29 15:37

    Method set

    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.

    Addressable and not addressable types

    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()
    }
    

    Variables of interface type are not addressable

    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)

    打赏 评论
  • duan19780629 2017-01-29 15:40

    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.

    打赏 评论
  • drd99007 2017-01-29 16:59

    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 :-)
    }
    
    打赏 评论

相关推荐 更多相似问题