上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
12下一页
返回列表 发新帖

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

[复制链接]
  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    637

    主题

    5189

    回帖

    6073

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6073

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2023-3-4 23:57:15 | 显示全部楼层 | 阅读模式

    原文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)的由来
    提示类型本身不实现接口,只能是类型的指针
    让我们看一个例子

    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接口,我们将得到一个有问题的错误

    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的

    s = &m
    fmt.Println(s)

    我们得到了期望的输出
    something

    所以我们得到这个编译的错误需要以下条件

    1.分配一个非指针的确切类型的值(或传递以及转换)
    2.一个接口类型将要被分配(或传递或转换)
    3.一个确切的实现了接口的这些方法,但是是指针接收者

    以下方案可以解决这个问题

    1.使用指针类型,指针类型的方法集将包含指针接收者的方法
    2.或将函数的指针接收者改为非指针接收者,因此非指针接收者的方法集也将包含该方法,这可能可以解决问题,也可能出现新的问题,就比如方法会修改值,而非指针接收者无法做到/

    结构和嵌入

    使用结构和嵌入的时候,实现接口的通常不是你,而是嵌入到你的类型,就像下面这个例子

    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具有这个方法集,所以接下来我们可以

    var s Stringer
    s = &m2

    我们可以让他工作,如果我们嵌入一个*MyType和使用非指针Mytype2

    type MyType2 struct {
        *MyType
    }
    
    m := MyType{value: "something"}
    m2 := MyType2{MyType: &m}
    
    var s Stringer
    s = m2

    无论我们嵌入(MyType或*MyType),如何我们使用指针MyType2她都可以正常工作

    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,在这个例子中断言不成立,来自上诉原因,但是我们会得到一个完全不一样的运行时错误

    m := MyType{value: "something"}
    
    var i interface{} = m
    fmt.Println(i.(Stringer))

    运行错误

    panic: interface conversion: main.MyType is not main.Stringer:
        missing method String

    尝试使用转换而不是类型断言,我们得到了我们正在讨论的编译时错误

    m := MyType{value: "something"}
    
    fmt.Println(Stringer(m))
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
  • TA的每日心情
    开心
    2024-3-13 10:14
  • 签到天数: 211 天

    [LV.7]常住居民III

    293

    主题

    3898

    回帖

    3819

    积分

    管理员

    积分
    3819

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-3-5 00:35:02 | 显示全部楼层
    看得我头疼

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


    而且整个看下来,不知道要干啥
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。/ 微信公众号:一之哥哥
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    637

    主题

    5189

    回帖

    6073

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6073

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2023-3-5 00:37:14 | 显示全部楼层

    这个...哥哥就别看了
    我写着也头疼
    核心其实就几句话
    一个结构只拥有自身方法
    但是结构的指针拥有结构的方法和指针的方法
    如果结构嵌入指针,就无论指针还是非指针都ok
    如果结构嵌入结构,使用指针方法就必须使用指针
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-3-13 10:14
  • 签到天数: 211 天

    [LV.7]常住居民III

    293

    主题

    3898

    回帖

    3819

    积分

    管理员

    积分
    3819

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-3-5 00:43:56 | 显示全部楼层
    李恒道 发表于 2023-3-5 00:37
    这个...哥哥就别看了
    我写着也头疼
    核心其实就几句话

    有这时间,不如去看看 GMP 模型、反射、切片、context。。。。。
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。/ 微信公众号:一之哥哥
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    637

    主题

    5189

    回帖

    6073

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6073

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2023-3-5 00:49:57 | 显示全部楼层
    王一之 发表于 2023-3-5 00:43
    有这时间,不如去看看 GMP 模型、反射、切片、context。。。。。

    我还没学到...
    刚学到接口
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2023-11-2 17:37
  • 签到天数: 275 天

    [LV.8]以坛为家I

    113

    主题

    450

    回帖

    969

    积分

    荣誉开发者

    积分
    969

    荣誉开发者油中2周年卓越贡献生态建设者

    发表于 2023-3-5 11:52:04 | 显示全部楼层
    道哥是要写go是吗
    I frequently record, because want to leave something.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    637

    主题

    5189

    回帖

    6073

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6073

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2023-3-5 13:24:32 | 显示全部楼层
    wwwwwllllk 发表于 2023-3-5 11:52
    道哥是要写go是吗

    想学一门后端了
    之前一直用nestjs冒充全栈
    k8s,docer啥的一点不会,sql都会的很少
    所以想挑个主流的好好学学
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2023-11-2 17:37
  • 签到天数: 275 天

    [LV.8]以坛为家I

    113

    主题

    450

    回帖

    969

    积分

    荣誉开发者

    积分
    969

    荣誉开发者油中2周年卓越贡献生态建设者

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

    但是我感觉道哥真牛逼,研究的真深,我觉得能用能写业务就好了对于初学者
    I frequently record, because want to leave something.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    637

    主题

    5189

    回帖

    6073

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6073

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

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


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

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2023-11-2 17:37
  • 签到天数: 275 天

    [LV.8]以坛为家I

    113

    主题

    450

    回帖

    969

    积分

    荣誉开发者

    积分
    969

    荣誉开发者油中2周年卓越贡献生态建设者

    发表于 2023-3-5 14:48:41 | 显示全部楼层
    李恒道 发表于 2023-3-5 14:31

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

    我有时候也会钻牛角尖,我困惑的地点搞不懂就很难受,但是我知道自己水平太菜,你现在发的内容我压根就看不懂也不想看懂,最好还是比如用了技术写了一个实用性的内容,我可能就感兴趣了
    I frequently record, because want to leave something.
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表