25|方法:方法集合与如何选择receiver类型?
该思维导图由 AI 生成,仅供参考
receiver 参数类型对 Go 方法的影响
- 深入了解
- 翻译
- 解释
- 总结
Go方法的receiver参数类型选择对方法的影响是一个重要的设计考量。文章首先介绍了receiver参数类型对方法的影响,通过对不同类型的receiver参数类型的分析,得出了选择receiver参数类型的两个原则。第一个原则是,如果要在方法中对receiver参数代表的类型实例进行修改,应选择\*T类型作为receiver参数的类型;第二个原则是,如果不需要在方法中对类型实例进行修改,一般情况下选择T类型作为receiver参数的类型,但如果receiver参数类型的size较大,选择\*T类型可能更好。此外,文章还介绍了方法调用时receiver参数的自动转换,以及方法集合(Method Set)的概念。这些原则和概念为读者提供了在选择receiver参数类型时的指导原则和理论基础。 文章还介绍了方法集合的概念,方法集合是用来判断一个类型是否实现了某接口类型的唯一手段,可以说,“方法集合决定了接口实现”。方法集合的概念在Go语言中的主要用途,就是用来判断某个类型是否实现了某个接口。通过对方法集合的分析,文章提出了选择receiver参数类型的第三个原则,即根据T类型是否需要实现某个接口来选择receiver参数类型。如果T类型需要实现某个接口,就应该使用T作为receiver参数的类型来满足接口类型方法集合中的所有方法。 总的来说,文章通过对receiver参数类型选择的原则和方法集合的概念进行了深入的讲解,为读者提供了在选择receiver参数类型时的指导原则和理论基础。同时,文章还提出了选择receiver参数类型的第三个原则,即根据T类型是否需要实现某个接口来选择receiver参数类型。这些内容对于理解和设计Go方法的receiver参数类型具有重要的指导意义。
《Tony Bai · Go 语言第一课》,新⼈⾸单¥59
全部留言(27)
- 最新
- 精选
- Geek_99b47cS 类型 和 *S 类型都没有包含方法,因为type S T 定义了一个新类型。 但是如果用 type S = T 则S和*S类型都包含两个方法。
作者回复: 👍,抢答正确:)
2021-12-10477 - 罗杰其实相比 Rust,Go 的糖更少,而且时而多,时而少,让开发者会很困惑,甚至前后矛盾。*T 和 T调用方法时编译器互相转换,哇,真贴心,真舒服。但是方法集合,又被 Go 反手打了一巴掌。的确解决了 C 语言的诸多问题,但对比 Rust 的一些处理方案,的确会让人不爽。
作者回复: 是有点这种感觉哈。
2021-12-10823 - liaomars老师: 如果 T 类型需要实现某个接口,那我们就要使用 T 作为 receiver 参数的类型,来满足接口类型方法集合中的所有方法。 这段描述感觉不对,根据上面举的例子来说,应该是使用 *T 作为 receiver参数的类型,来满足接口类型方法集合中的所有方法。
作者回复: 我再举例说一下“如果 T 类型需要实现某个接口” 这句的含义。现在有一个接口类型I,一个自定义非接口类型T,这句的含义就是 我们希望 var i I var t T i = t 这段代码是ok的。即t可以赋值给i。 如果是*T实现了I,那么不能保证T也会实现I。所以我们在设计一个自定义类型T的方法时,考虑是否T需要实现某个接口。如果需要,方法receiver参数的类型应该是T。如果T不需要,那么用*T或T就都可以了。
2021-12-10514 - Calvin老师,dumpMethodSet 函数只能统计导出方法的,有没有办法把非导出方法的也统计出来?
作者回复: 能不能得到非导出方法的信息取决于reflect包是否提供对应的能力,要不留个作业:探索一下reflect包,看是否能得到非导出方法的列表。:)
2021-12-1124 - 左耳朵东如果因为 T 类型需要实现某一接口而使用 T 作为 receiver 参数的类型,那如果我想把在方法里对 t 的修改反映到原 T 类型实例上,何做到呢?
作者回复: 其实这里的“T类型是否要实现接口”的含义是是否存在将T类型值赋值给接口类型的情况。如果存在,则必须用T作为receiver,如果不存在,按原则1和2。我让编辑更新了原文,增加了说明。希望增加后大家理解起来更容易些。
2021-12-1153 - 在下宝龙、S类型和*S类型都是 空方法,因为S是新的类型,它不能调用T的方法,必须显示转换之后才可以调用,所以本身的S或*S类型都不具有任何的方法
作者回复: 👍
2021-12-103 - 靠近我,温暖你S 类型 和 *S 类型都没有包含方法,因为type S T 定义了一个新类型。 但是如果用 type S = T 则S和*S类型都包含两个方法。
作者回复: 👍
2023-01-29归属地:河南2 - 文经白老师,这课有两个疑问: 1. 当函数传递T类型的参数时,编译有办法判断对T类型是否有修改吗?如果没有修改的话,是否可以把参数转化为类似常量指针的方式引用,例如传递一个数组,如果没对数组修改 ,完全可以只传递一个指针。 2. 对于receiver选择的原则三:对T类型的限制比 *T 类型多,是不是因为有些时候一个T类型的对象无法获取它的地址,例如const 对象,但是一个T的指针类型,总是可以转换为 T类型的对象。
作者回复: 1. 好像没有这个优化。 2. 我不能确定,但你的想法很新颖。
2022-01-062 - 111测试一下 import ( "fmt" "reflect" ) type T struct{} func (T) M1() {} func (T) M2() {} type S T func dumpMethodSet(i interface{}) { dynTyp := reflect.TypeOf(i) if dynTyp == nil { fmt.Printf("there is no dynamic type\n") return } n := dynTyp.NumMethod() if n == 0 { fmt.Printf("%s's method set is empty!\n", dynTyp) return } fmt.Printf("%s's method set:\n", dynTyp) for j := 0; j < n; j++ { fmt.Println("-", dynTyp.Method(j).Name) } fmt.Printf("\n") } func main() { var s S dumpMethodSet(s) } ---------------------------------- S's method set is empty! *S's method set is empty! S 类型 和 *S 类型都没有包含方法 看来 S 是一个新类型,没有“继承”到T的方法
作者回复: 正确✅
2023-06-08归属地:北京1 - 夏天方法接收者类型选择三个原则 1.如果需要修改接收者本身,传指针 *T 2.如果接受者本身较为复杂,传指针 *T,避免拷贝 3.*T 的方法集合是包含 T 的方法集合。*T 范围更大 go 文档不推荐混合使用,一般还是用 T* 吧。除非明确需要不改动 T 本身
作者回复: 👍
2022-11-21归属地:北京1