Golang中的方法集问题

问题提要

之前写代码的时候遇到了一个问题:自己编写了一个接口,然后又写了一个结构体实现这个接口,在通过函数调用接口方法时出现了问题。
代码如下:

type Validator interface  {
  Valid() bool
}

type LoginInput struct {
  Username string
  Password string
}

func (input *LoginInput) Valid() bool {
  // 一些检验逻辑
  // 返回校验结果
}

func Handle(v Validator) {
  res := v.Valid()
  // 根据校验结果做一些逻辑处理
}

func main() {
  // 对具体过程做了提炼,最终逻辑一致
  input := LoginInput{Username: "XXX", Password: "YYY"}
  Handle(input)
}

main中调用Handle()时传参失败,Goland提示消息如下:Cannot use 'input' (type LoginInput) as type ValidatorType does not implement 'Validator' as 'Valid' method has a pointer receiver

解决方法其实很简单,就是调用Handle()不要传值,要传指针。把调用改成这样就行:Handle(&input)

但这是为什么呢?回去翻了翻书,发现是因为方法集

什么是方法集

我们先来看看Golang官方对它的描述:

https://golang.google.cn/ref/spec#Method_sets
A type may have a method set associated with it. The method set of an interface type is its interface. The method set of any other type T consists of all methods declared with receiver type T. The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T). Further rules apply to structs containing embedded fields, as described in the section on struct types. Any other type has an empty method set. In a method set, each method must have a unique non-blank method name.
The method set of a type determines the interfaces that the type implements and the methods that can be called using a receiver of that type.
一个类型会有一个与它关联的方法集。interface类型的方法集就是接口本身。其他任意类型T的方法集由接收者为T类型的全部方法构成。对应的指针类型*T的方法集是由接收者为T*T的全部方法构成的(也就是说,它也包含了T的方法集)。更多的规则应用在包含嵌入字段的结构体上,就像struct types章节中描述的一样。任何其他类型都有一个空的方法集。在方法集中,每个方法必须具有唯一的非空方法名。
类型的方法集确定类型实现的接口以及可以使用该类型的接收器调用的方法。

总结一下官方文档表述的意思,我们得到如下一张表:

变量类型 方法接收器类型
T (t T)
*T (t T) + (t *T)

对于T类型,它的方法集只包含接收者类型是T的方法;而对于*T类型,它的方法集则包含接收者为T*T类型的方法,也就是全部方法
只有一个类型的方法集完全涵盖了接口的方法集后,这个类型才会被认为是接口的实现类型。
从这里可以看出来,我们最开始的代码就是因为LoginInput类型的方法集中没有notify方法,所以函数调用失败了。

结构体的方法调用与方法集之间的关系

其实到这里就会有个疑问:平时调用方法时,无论变量类型是值类型还是指针类型都能调用成功,也没出过问题啊。
这里其实是Golang的一个语法糖:在使用选择器(Selectors)调用方法时,编译器会帮你做好取址或取值的操作的。
下面通过代码说明一下这个关系:

type StructA struct {}

func (s StructA) ValueReceiver () {}

func (s *StructA) PointReceiver () {}

func main() {
  value := StructA{}
  point := &value
  // 编译器不做处理,就是value.ValueReceiver()
  value.ValueReceiver()
  // 其实是(&value).ValueReceiver()的简便写法
  value.PointReceiver()
  // 其实是(*point).ValueReceiver()的简便写法
  point.ValueReceiver()
  // 编译器不做处理,就是point.ValueReceiver()
  point.PointReceiver()
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容