去,X不执行Y(…方法有一个指针接收器)

关于这个“ X没有实现Y(…方法有一个指针接收器) ”的问题已经有了几个问题,但对我来说,他们似乎是在谈论不同的事情,而不适用于我的具体情况。

所以,我没有把这个问题做得非常具体,而是把它放在一个宽泛而抽象的地方 – 好像有几种不同的情况可以使这个错误发生,有人可以把它总结出来吗?

也就是说,如何避免这个问题,如果发生,有什么可能呢? 谢谢。

当您尝试将具体types分配或传递(或转换)为接口types时,会出现此编译时错误; 而types本身并没有实现这个接口,只有一个指向types指针

我们来看一个例子:

type Stringer interface { String() string } type MyType struct { value string } func (m *MyType) String() string { return m.value } 

Stringer接口types只有一个方法: String() 。 存储在接口值Stringer中的任何值都必须具有此方法。 我们还创build了一个MyType ,并且用指针接收器创build了一个方法MyType.String() 。 这意味着String()方法在*MyTypetypes的方法集中 ,但不在MyType

当我们试图将一个MyType的值赋给一个Stringertypes的variables时,我们得到了这个错误:

 m := MyType{value: "something"} var s Stringer s = m // cannot use m (type MyType) as type Stringer in assignment: // MyType does not implement Stringer (String method has pointer receiver) 

但是,如果我们试图给Stringer分配一个*MyTypetypes的值,

 s = &m fmt.Println(s) 

我们得到预期的结果(在Go Playground上试试):

 something 

所以需要得到这个编译时错误:

  • 被指定(或传递或转换)的非指针具体types的值
  • 被分配给(或传递给或转换成)
  • 具体types有接口所需的方法,但带有指针接收器

解决问题的可能性:

  • 必须使用指向该值的指针,其方法集将包含指针接收方的方法
  • 或者接收器types必须改为非指针 ,所以非指针具体types的方法集合也将包含方法(从而满足接口)。 这可能是也可能不是可行的,就好像该方法必须修改该值,非指针接收器不是一个选项。

结构和embedded

当使用结构和embedded时 ,通常不是实现一个接口(提供一个方法实现)的“你”,而是你embedded到你的struct的types。 像这个例子一样:

 type MyType2 struct { MyType } m := MyType{value: "something"} m2 := MyType2{MyType: m} var s Stringer s = m2 // Compile-time error again 

再次,编译时错误,因为MyType2的方法集不包含embedded的MyTypeString()方法,只有*MyType2的方法集,所以下面的工作(在Go Playground上试试它):

 var s Stringer s = &m2 

我们也可以使它工作,如果我们embedded*MyType并且只使用一个非指针 MyType2 (在Go Playground上试试):

 type MyType2 struct { *MyType } m := MyType{value: "something"} m2 := MyType2{MyType: &m} var s Stringer s = m2 

此外,无论我们embedded( MyType*MyType ),如果我们使用指针*MyType2 ,它将始终工作(在Go Playground上尝试):

 type MyType2 struct { *MyType } m := MyType{value: "something"} m2 := MyType2{MyType: &m} var s Stringer s = &m2 

规范中的相关部分(来自部分Structtypes ):

给定一个结构typesS和一个名为T的types,所提升的方法包含在结构体的方法集中,如下所示:

  • 如果S包含一个匿名字段T ,则S*S的方法集合都包含带有接收者T推广方法。 *S的方法集合还包含了接收者*T推广方法。
  • 如果S包含匿名字段*T ,则S*S的方法集都包含带有接收者T*T推广方法。

换句话说,如果我们embedded一个非指针types,那么非指针embedded的方法集合只能得到非指针接收者(来自embeddedtypes)的方法。

如果我们embedded一个指针types,那么非指针embedded器的方法集合将获得具有指针和非指针接收器(来自embeddedtypes)的方法。

如果我们使用一个指向embedded式的指针值,不pipeembedded式types是否为指针,指向embedded式指针的方法集总是获取指针和非指针接收器(来自embeddedtypes)的方法。

注意:

有一个非常相似的情况,即当你有一个包装一个MyType值的接口值,并且你试图从它中键入断言另一个接口值, Stringer 。 在这种情况下,由于上述原因,断言不会成立,但是我们得到一个稍微不同的运行时错误:

 m := MyType{value: "something"} var i interface{} = m fmt.Println(i.(Stringer)) 

运行时间恐慌(在Go游乐场尝试):

 panic: interface conversion: main.MyType is not main.Stringer: missing method String 

试图转换而不是types断言,我们得到了编译时错误,我们正在谈论:

 m := MyType{value: "something"} fmt.Println(Stringer(m))