李恒道 发表于 2023-3-4 23:57:15

golang X does not implement Y (... method has a pointer receiver)

原文https://stackoverflow.com/questions/40823315/x-does-not-implement-y-method-has-a-pointer-receiver
# 正文
当你尝试将一个确切类型分配或转换接口类型时,在编译时会报错
也就是X does not implement Y (method has a pointer receiver)的由来
提示类型本身不实现接口,只能是类型的指针
让我们看一个例子
```go
type Stringer interface {
    String() string
}

type MyType struct {
    value string
}

func (m *MyType) String() string { return m.value }
```
Stringer接口只有一个方法,任何存储在Stringer接口的值都必须实现这个方法,我们创建一个MyType.String()方法是一个指针接收者,这意味着String方法在*MyType的方法集中,而非MyType的方法集中
当我们试图将MyType变量分配给Stringer接口,我们将得到一个有问题的错误
```go
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,一切都是ok的
```go
s = &m
fmt.Println(s)
```
我们得到了期望的输出
something
## 所以我们得到这个编译的错误需要以下条件
1.分配一个非指针的确切类型的值(或传递以及转换)
2.一个接口类型将要被分配(或传递或转换)
3.一个确切的实现了接口的这些方法,但是是指针接收者
## 以下方案可以解决这个问题
1.使用指针类型,指针类型的方法集将包含指针接收者的方法
2.或将函数的指针接收者改为非指针接收者,因此非指针接收者的方法集也将包含该方法,这可能可以解决问题,也可能出现新的问题,就比如方法会修改值,而非指针接收者无法做到/
# 结构和嵌入
使用结构和嵌入的时候,实现接口的通常不是你,而是嵌入到你的类型,就像下面这个例子
```go
type MyType2 struct {
    MyType
}

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

var s Stringer
s = m2 // Compile-time error again
```
又一次出现同样的编译错误,因为方法集Mytype2嵌入的MyType不包含String(),仅有*MyType2具有这个方法集,所以接下来我们可以
```go
var s Stringer
s = &m2
```
我们可以让他工作,如果我们嵌入一个*MyType和使用非指针Mytype2
```go
type MyType2 struct {
    *MyType
}

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

var s Stringer
s = m2
```
无论我们嵌入(MyType或*MyType),如何我们使用指针MyType2她都可以正常工作
```go
type MyType2 struct {
    *MyType
}

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

var s Stringer
s = &m2
```
规范中的相关部分https://golang.org/ref/spec#Struct_types
给定一个类型S与嵌入类型T,提升的方法包含在结构的方法集的规则如下所示
如果S包含匿名字段T,则方法集S和指针S都包含T的接受者提升方法,*S还包含   指针T的接收者提升方法
如果S包含匿名字段指针T,则方法集S以及 指针S都包括T和指针T的提升方法
换句话说,如果我们嵌入了一个非指针类型,那么嵌入该非指针嵌入的结构的方法集只能得到非指针接收者的方法(来自嵌入类型)
如果我们嵌入了一个指针类型,嵌入该指针的结构的方法集将同时获得指针和非指针接收器的方法(来自嵌入类型)
如果我们使用嵌入结构的结构的指针值,无论嵌入类型是否是指针,该指针的方法集总是获得指针的和非指针接收者的方法(来自嵌入类型)
提示:
有一个非常近似的情况,当你有一个接口类型包裹着MyType值,和你尝试将他断言另一个接口值Stringer,在这个例子中断言不成立,来自上诉原因,但是我们会得到一个完全不一样的运行时错误
```go
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
```
尝试使用转换而不是类型断言,我们得到了我们正在讨论的编译时错误
```go
m := MyType{value: "something"}

fmt.Println(Stringer(m))
```

王一之 发表于 2023-3-5 00:35:02

看得我头疼

很多东西都是“设计如此”,哥哥太纠结了


而且整个看下来,不知道要干啥

李恒道 发表于 2023-3-5 00:37:14

王一之 发表于 2023-3-5 00:35
看得我头疼
这个...哥哥就别看了
我写着也头疼
核心其实就几句话
一个结构只拥有自身方法
但是结构的指针拥有结构的方法和指针的方法
如果结构嵌入指针,就无论指针还是非指针都ok
如果结构嵌入结构,使用指针方法就必须使用指针

王一之 发表于 2023-3-5 00:43:56

李恒道 发表于 2023-3-5 00:37
这个...哥哥就别看了
我写着也头疼
核心其实就几句话

有这时间,不如去看看 GMP 模型、反射、切片、context。。。。。

李恒道 发表于 2023-3-5 00:49:57

王一之 发表于 2023-3-5 00:43
有这时间,不如去看看 GMP 模型、反射、切片、context。。。。。

{:4_98:}我还没学到...
刚学到接口

wwwwwllllk 发表于 2023-3-5 11:52:04

道哥是要写go是吗

李恒道 发表于 2023-3-5 13:24:32

wwwwwllllk 发表于 2023-3-5 11:52
道哥是要写go是吗

想学一门后端了
之前一直用nestjs冒充全栈
k8s,docer啥的一点不会,sql都会的很少
所以想挑个主流的好好学学

wwwwwllllk 发表于 2023-3-5 13:50:23

李恒道 发表于 2023-3-5 13:24
想学一门后端了
之前一直用nestjs冒充全栈
k8s,docer啥的一点不会,sql都会的很少


但是我感觉道哥真牛逼,研究的真深,我觉得能用能写业务就好了对于初学者

李恒道 发表于 2023-3-5 14:31:58

wwwwwllllk 发表于 2023-3-5 13:50
但是我感觉道哥真牛逼,研究的真深,我觉得能用能写业务就好了对于初学者 ...

相反
我这种学习方式经常被抨击...
我属于那种我不完全理解一门语言的概念和大量的细节就完全写不出代码的人
以至于TS我甚至学了三个月才写业务代码
Golang按目前进度可能需要半年...
(类似于健身房那个冷笑话
一个人每天去健身房看别人锻炼
坚持一个月之后终于开始尝试跳绳

wwwwwllllk 发表于 2023-3-5 14:48:41

李恒道 发表于 2023-3-5 14:31

相反
我这种学习方式经常被抨击...


我有时候也会钻牛角尖,我困惑的地点搞不懂就很难受,但是我知道自己水平太菜,你现在发的内容我压根就看不懂也不想看懂,最好还是比如用了技术写了一个实用性的内容,我可能就感兴趣了{:4_115:}
页: [1] 2
查看完整版本: golang X does not implement Y (... method has a pointer receiver)