去,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()
方法在*MyType
types的方法集中 ,但不在MyType
。
当我们试图将一个MyType
的值赋给一个Stringer
types的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
分配一个*MyType
types的值,
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的MyType
的String()
方法,只有*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 ):
给定一个结构types
S
和一个名为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))