关于这个“X 没有实现 Y(...方法有一个指针接收器)”这个问题已经有几个问答,但对我来说,他们似乎在谈论不同的事情,而不适用于我的具体情况。
因此,我没有让问题变得非常具体,而是让它变得广泛而抽象——似乎有几种不同的情况会导致这个错误发生,有人可以总结一下吗?
即,如何避免问题,如果发生,有哪些可能性?谢谢。
最佳答案
当您尝试将具体类型分配或传递(或转换)为接口(interface)类型时,会出现此编译时错误;而类型本身并没有实现接口(interface),只是一个指向类型的指针。
简短摘要:安 assignment如果被分配的值实现了它被分配给的接口(interface),则到接口(interface)类型的变量是有效的。如果它的 method set 实现它是接口(interface)的超集。指针类型的方法集包括具有指针和非指针接收器的方法。非指针类型的方法集仅包括具有非指针接收器的方法。
让我们看一个例子:
type Stringer interface {
String() string
}
type MyType struct {
value string
}
func (m *MyType) String() string { return m.value }
Stringer
接口(interface)类型只有一种方法:String()
.存储在接口(interface)值 Stringer
中的任何值必须有这个方法。我们还创建了一个 MyType
,我们创建了一个方法 MyType.String()
与 指针接收者。这意味着 String()
方法在 method set的*MyType
类型,但不属于 MyType
.当我们尝试分配
MyType
的值时到 Stringer
类型的变量,我们得到了有问题的错误: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)
但是如果我们尝试分配一个类型为 *MyType
的值,一切都会好起来的。至 Stringer
:s = &m
fmt.Println(s)
我们得到了预期的结果(在 Go Playground 上试试):something
所以得到这个编译时错误的要求:解决问题的可能性:
结构和嵌入
使用时 structs and embedding ,通常实现接口(interface)(提供方法实现)的不是“您”,而是您嵌入到
struct
中的类型。 .就像在这个例子中:type MyType2 struct {
MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: m}
var s Stringer
s = m2 // Compile-time error again
再次,编译时错误,因为方法集MyType2
不包含 String()
嵌入方法MyType
,只有*MyType2
的方法集,因此以下工作(在 Go Playground 上尝试):var s Stringer
s = &m2
我们也可以让它工作,如果我们嵌入 *MyType
并且只使用非指针 MyType2
(在 Go Playground 上试试):type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = m2
此外,无论我们嵌入什么( MyType
或 *MyType
),如果我们使用指针 *MyType2
,它将始终有效(在 Go Playground 上尝试):type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = &m2
规范中的相关部分(来自部分 Struct types ):Given a struct type
S
and a type namedT
, promoted methods are included in the method set of the struct as follows:
- If
S
contains an anonymous fieldT
, the method sets ofS
and*S
both include promoted methods with receiverT
. The method set of*S
also includes promoted methods with receiver*T
.- If
S
contains an anonymous field*T
, the method sets ofS
and*S
both include promoted methods with receiverT
or*T
.
所以换句话说:如果我们嵌入一个非指针类型,那么非指针嵌入器的方法集只会获取带有非指针接收器的方法(来自嵌入类型)。
如果我们嵌入一个指针类型,则非指针嵌入器的方法集获取具有指针和非指针接收器的方法(来自嵌入类型)。
如果我们使用指向嵌入器的指针值,无论嵌入类型是否为指针,指向嵌入器的指针的方法集总是同时获取具有指针和非指针接收器的方法(来自嵌入类型)。
注:
有一种非常相似的情况,即当您有一个包含值
MyType
的接口(interface)值时,然后您尝试 type assert来自它的另一个接口(interface)值,Stringer
.在这种情况下,由于上述原因,断言将不成立,但我们会得到一个稍微不同的运行时错误:m := MyType{value: "something"}
var i interface{} = m
fmt.Println(i.(Stringer))
运行时 panic (在 Go Playground 上试试):panic: interface conversion: main.MyType is not main.Stringer:
missing method String
尝试转换而不是类型断言,我们得到了我们正在谈论的编译时错误:m := MyType{value: "something"}
fmt.Println(Stringer(m))
关于pointers - X 没有实现 Y (...方法有一个指针接收器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40823315/