pointers - X 没有实现 Y (...方法有一个指针接收器)

标签 pointers go methods interface

关于这个“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
所以得到这个编译时错误的要求:
  • 正在分配(或传递或转换)的非指针具体类型的值
  • 分配给(或传递给或转换为)的接口(interface)类型
  • 具体类型具有接口(interface)所需的方法,但带有指针接收器

  • 解决问题的可能性:
  • 必须使用指向该值的指针,其方法集将包含具有指针接收器的方法
  • 或者接收器类型必须改为非指针,因此非指针具体类型的方法集也将包含该方法(从而满足接口(interface))。这可能可行,也可能不可行,就好像该方法必须修改值一样,非指针接收器不是一种选择。

  • 结构和嵌入
    使用时 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 named T, promoted methods are included in the method set of the struct as follows:

    • If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
    • If S contains an anonymous field *T, the method sets of S and *S both include promoted methods with receiver T 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/

    相关文章:

    c++ - 智能指针(unique_ptr)代替原始指针作为类成员

    file - 如何在 Go 中的 io.Reader 上测试 EOF?

    c# - 如何动态找出所有具有自定义属性的方法

    c# - Xamarin WCF BasicHttpBinding-未实现方法或操作

    c - 迭代c中通过引用传递的数组

    c - 如何使用strcat()函数?

    c++ - C++ 中的指针和多维数组

    go - 转到 channel 死锁未发生

    go - 如何提取unix时间戳并获取日期

    javascript - Angular v5 英雄教程中 hero.service.ts 的 deleteHero 方法中的管道编号( | 编号)是什么