26|方法:如何用类型嵌入模拟实现“继承”?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
Go语言中的类型嵌入是一项强大的特性,可以模拟实现“继承”,通过嵌入其他类型的方法来扩展自定义类型的功能。本文首先介绍了接口类型的类型嵌入,通过案例展示了如何在一个接口类型中嵌入另一个接口类型,实现接口的组合。随后,文章详细介绍了结构体类型的类型嵌入,解释了这种方式对新定义的类型的方法集合的影响。文章还提到了Go语言中的组合设计哲学,强调了类型嵌入的重要性和灵活性。通过实例和讲解清晰地展示了类型嵌入的原理和方法集合的变化,为读者提供了深入理解和应用该特性的基础。文章通过对接口类型和结构体类型的类型嵌入进行详细讲解,展示了Go语言中类型嵌入的灵活性和强大功能。读者可以从中快速了解并掌握类型嵌入的使用方法和技术特点,为日后的Go语言开发提供了有力的参考和指导。 在文章中,我们学习了类型嵌入相关的知识,包括接口类型和结构体类型的类型嵌入。类型嵌入对类型方法集合的影响是我们日常进行方法设计时必须要考虑到的重要因素。类型嵌入分为两种,一种是接口类型的类型嵌入,另一种是结构体类型的类型嵌入。通过实例和讲解,我们了解到类型嵌入实际上是一种组合,更具体地说是组合思想下代理模式的运用。最后,我们还总结了基于非接口类型的defined类型创建的新defined类型不会继承原类型的方法集合,而通过类型别名定义的新类型则和原类型拥有相同的方法集合。 通过本文的学习,读者可以快速了解并掌握类型嵌入的使用方法和技术特点,为日后的Go语言开发提供了有力的参考和指导。文章内容丰富,深入浅出,适合对Go类型嵌入感兴趣的读者。
《Tony Bai · Go 语言第一课》,新⼈⾸单¥59
全部留言(30)
- 最新
- 精选
- 奕S2 不是嵌入的,相当的正常书写的字段,所有没有 对应接口的方法集合
作者回复: ✅
2021-12-14357 - liaomars带有类型嵌入的结构体 S1 与不带类型嵌入的结构体 S2 是否是等价的,如不等价,区别在哪里? 这两个S1与S2是不等价的,区别是:S1结构体能调用代理嵌入类型的所有方法,S2结构体是没有代理嵌入类型方法。
作者回复: 正确✅
2021-12-1312 - 13693113483可不可以这样认为,直接 T1 *t2 I 我们可以理解为是继承,里面所有方法可以调用,然而: T1 T1 t2 *t2 I I 这种是组合,如果想调用里面的方法要用 S2.I.M1()
作者回复: 两种本质上都是组合。第一种可以理解为一种“语法糖”,无需再在外层结构上重新定义方法并代理给内部字段。第二种从能力上讲和第一种没有本质区别,只是需要开发者自己在外层封一层方法,然后调用字段对应的方法。
2022-06-236 - 菠萝吹雪—Code这篇真干,赞,需要多看几遍
作者回复: 👍
2022-08-19归属地:北京3 - Aeins结构体类型,两种不同方式嵌套接口类型。 由于接口类型嵌套允许重名方法,I 接口有三个方法。SI 嵌套 I,SI 也有三个方法 结构体嵌套不允许重名,M 方法,被自动隐藏了?,SI12嵌套 I1, I2, SI12 只有两个方法 package main import ( "fmt" "reflect" ) type I1 interface { M() M1() } type I2 interface { M() M2() } type I interface { I1 I2 } type SI struct { I } type SI12 struct { I1 I2 } func main() { var si SI var si12 SI12 DumpMethodSet(si) DumpMethodSet(si12) } 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") } ============ main.SI's method set: - M - M1 - M2 main.SI12's method set: - M1 - M2
作者回复: 问题非常好!👍 我们知道:一个类型的方法集合中的方法都可以被这个类型实例所调用。反过来说,只有能被类型实例直接调用的方法才能进入其方法集合。 在你的例子中,SI12嵌入了I1和I2,这就造成了I1和I2的方法集合的交集M在SI12中存在了歧义。当使用SI12的实例调用M时,比如: var s SI12 s.M() // go编译器会报错!不确定究竟是调用s.I1.M还是s.I2.M 于是M因这种未决的歧义性而不能被列入SI12的方法集合中。
2022-05-3023 - Geek_99b47cS1's method set total 1, detail method : -- M1 S2's method set is empty 这是为啥啊
作者回复: 建议再重新学习一下25讲与26讲。只有自己理解后,知识才是自己的。
2021-12-1323 - 不求闻达不等价,S2 不是嵌入的是defined 类型。defined 类型创建的新 defined 类型不会继承原类型的方法集合
作者回复: 正确✅👍
2023-04-06归属地:上海2 - Fan()类型 *T 的方法集合 = *T1 的方法集合 + *T2 的方法集合 对这个不太理解... 有点懵逼. 这个原理能细讲一下吗?
作者回复: 这个没有什么原理可讲,Go语言就是这么规定的:)。
2022-04-032 - Calvin不等价,dumpMethodSet 结果就不一样: S1's method set: - M1 *S1's method set: - M1 S2's method set is empty! *S2's method set is empty!
作者回复: 👍
2021-12-202 - lesserrorTony bai 老师,我看打印出的方法集合中都有类似这样的输出:*main.T's 。后面会讲解一下这种语法输出吗? 对于课后问题,我觉得用一下老师的 dumpMethodSet 函数 就能很容易看出区别了。 package main import ( "fmt" "reflect" ) type T1 int type t2 struct{ n int m int } type I interface { M1() } type S1 struct { T1 *t2 I a int b string } type S2 struct { T1 T1 t2 *t2 I I a int b string } func main() { var s1 S1 var ps1 *S1 var s2 S2 var ps2 *S2 dumpMethodSet(s1) dumpMethodSet(ps1) dumpMethodSet(s2) dumpMethodSet(ps2) } 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") }
作者回复: *main.T其实也是一种指针类型,还是等我的加餐吧:(。
2021-12-1422