pointers - X不实现Y(…方法具有指针接收器)

标签 pointers go methods interface

关于“x不实现y(…方法有一个指针接收器)“事情,但对我来说,他们似乎在谈论不同的事情,而不适用于我的具体情况。
所以,我不是把这个问题说得很具体,而是把它说得宽泛而抽象--似乎有几种不同的情况会导致这个错误发生,有人能总结一下吗?
也就是说,如何避免这个问题,如果它发生了,有什么可能性?谢谢。

最佳答案

当您试图将具体类型分配或传递(或转换)给接口类型时,会出现此编译时错误;而该类型本身并没有实现接口,只是指向该类型的指针。
让我们看一个例子:

type Stringer interface {
    String() string
}

type MyType struct {
    value string
}

func (m *MyType) String() string { return m.value }

Stringer接口类型只有一个方法:String()。存储在接口值Stringer中的任何值都必须具有此方法。我们还创建了一个MyType,并使用指针接收器创建了一个方法MyType.String()。这意味着String()方法是*MyType类型的method set方法,而不是MyType类型的Go Playground方法。
当我们试图将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)

我们得到了预期的结果(在structs and embedding上试试):
something

所以得到这个编译时错误的要求是:
正在分配(或传递或转换)的非指针具体类型的值
被指派(或传递给或转换给)的接口类型
具体类型具有所需的接口方法,但具有指针接收器
解决问题的可能性:
必须使用指向该值的指针,其方法集将包括带有指针接收器的方法
或者接收器类型必须更改为非指针,因此非指针具体类型的方法集也将包含该方法(从而满足接口)。这可能可行,也可能不可行,就好像方法必须修改值一样,非指针接收器不是一个选项。
结构和嵌入
当使用Go Playground时,通常实现接口(提供方法实现)的不是“您”,而是嵌入到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),如果我们使用指针,它都会一直工作(在Struct types上试试):
type MyType2 struct {
    *MyType
}

m := MyType{value: "something"}
m2 := MyType2{MyType: &m}

var s Stringer
s = &m2

规范中的相关章节(来自type assert章节):
给定一个结构类型*MyType2和一个名为S的类型,提升的方法包含在结构的方法集中,如下所示:
如果T包含匿名字段S,则TS的方法集都包括带有receiver*S的提升方法。T的方法集还包括带有接收器*S的提升方法。
如果*T包含匿名字段S,则*TS的方法集都包括带有receiver*ST的提升方法。
所以换句话说:如果我们嵌入一个非指针类型,非指针嵌入器的方法集只获取具有非指针接收器的方法(从嵌入类型)。
如果我们嵌入一个指针类型,则非指针嵌入器的方法集将获取同时具有指针和非指针接收器(来自嵌入类型)的方法。
如果我们使用指向embedder的指针值,则不管嵌入类型是否为指针,指向embedder的指针的方法集始终获取同时具有指针接收器和非指针接收器(来自嵌入类型)的方法。
注:
有一个非常相似的情况,即当您有一个包装*T值的接口值,并且您试图从中Go Playground另一个接口值,MyType。在这种情况下,由于上述原因,断言将不起作用,但我们得到的运行时错误略有不同:
m := MyType{value: "something"}

var i interface{} = m
fmt.Println(i.(Stringer))

运行时死机(在上试试):
panic: interface conversion: main.MyType is not main.Stringer:
    missing method String

尝试转换而不是类型assert时,会出现我们所说的编译时错误:
m := MyType{value: "something"}

fmt.Println(Stringer(m))

关于pointers - X不实现Y(…方法具有指针接收器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58074254/

相关文章:

amazon-web-services - 为什么在此AWS Lambda部署包中找不到处理程序脚本?

html - 我无法在 HTML 上查看所有 MySQL 表数据

java - 如何从单独的类java调用方法

java - 方法(正确)将变量声明为 0 但我不明白为什么?

c - 它不允许我将变量存储到结构中的数组

C编程: dereferencing pointers

c++ - 如何使用字符串(字符数组)初始化 char 指针而不是整数数组的 int 指针?

c - 简单的 C 指针说明

mutex - 如何等待低延迟的线程?

python - 在类 Python 之外定义类方法