关于这个“X 没有实现 Y(...方法有一个指针接收器)”这个问题已经有几个问答,但对我来说,他们似乎在谈论不同的事情,而不适用于我的具体情况。
因此,我没有让问题变得非常具体,而是让它变得广泛而抽象——似乎有几种不同的情况会导致这个错误发生,有人可以总结一下吗?
即,如何避免问题,如果发生,有哪些可能性?谢谢。
最佳答案
当您尝试将具体类型分配或传递(或转换)为接口(interface)类型时,会出现此编译时错误;而类型本身并没有实现接口(interface),只是一个指向类型的指针。
简短摘要: 接口(interface)类型变量的 assignment 是有效的,如果被分配的值实现了它分配给的接口(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()
方法在 *MyType
类型的 method set 中,但不在 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
的方法集,只有 0x2518122431341 的方法集在 14231341 之后才起作用(1412313123)var s Stringer
s = &m2
我们也可以让它工作,如果我们嵌入 *MyType2
并且只使用一个非指针 *MyType
(在 Go Playground 上试试):type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = m2
此外,无论我们嵌入什么(MyType2
或 MyType
),如果我们使用指针 *MyType
,它将始终有效(在 0x2518122133 上尝试)type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = &m2
规范中的相关部分(来自部分 Go Playground ):所以换句话说:如果我们嵌入一个非指针类型,那么非指针嵌入器的方法集只会获取带有非指针接收器的方法(来自嵌入类型)。
如果我们嵌入一个指针类型,则非指针嵌入器的方法集获取具有指针和非指针接收器的方法(来自嵌入类型)。
如果我们使用指向嵌入器的指针值,无论嵌入类型是否为指针,指向嵌入器的指针的方法集总是同时获取具有指针和非指针接收器的方法(来自嵌入类型)。
注:
有一个非常相似的情况,即当您有一个包含
*MyType2
值的接口(interface)值,并且您尝试从中获取另一个接口(interface)值 MyType
Go Playground 时。在这种情况下,由于上述原因,断言将不成立,但我们会得到一个略有不同的运行时错误:m := MyType{value: "something"}
var i interface{} = m
fmt.Println(i.(Stringer))
运行时 panic (在 Struct types 上尝试):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/