内容简介:Go 语言没有对象的概念,但是 struct 类型有着和对象类似的特性。struct 类型可以定义自己的属性和方法。这篇文章我们来总结下 Go 语言中关于 “继承” 和多态的概念。嵌入类型是指将已有的类型直接声明在新的结构类型里。不像 Java、C++ 等语言,Go 语言没有继承,但是可以通过上面的代码定义了两个结构体 User 和 Admin,Admin 有一个匿名成员 User,因为是匿名,所以类型即名称。将 User 嵌入 Admin,Admin 是被嵌入的类型,也称
『就要学习 Go 语言』系列 -- 第 25 篇分享好文
Go 语言没有对象的概念,但是 struct 类型有着和对象类似的特性。struct 类型可以定义自己的属性和方法。这篇文章我们来总结下 Go 语言中关于 “继承” 和多态的概念。
嵌入类型
嵌入类型是指将已有的类型直接声明在新的结构类型里。不像 Java 、C++ 等语言,Go 语言没有继承,但是可以通过 组合 的方式实现代码的复用。
type User struct { Name string Email string } type Admin struct { User Level string } func (u *User) Speak() { fmt.Println("I am user",u.Name) } 复制代码
上面的代码定义了两个结构体 User 和 Admin,Admin 有一个匿名成员 User,因为是匿名,所以类型即名称。将 User 嵌入 Admin,Admin 是被嵌入的类型,也称 外部类型 ,User 是 内部类型 。Speak() 是 User 的方法。
通过嵌入,内部类型的属性、方法,可以为外部类型所有,就好像是外部类型自己的一样。此外,外部类型还可以定义自己的属性和方法,甚至可以定义与内部相同的方法,这样内部类型的方法就会被“屏蔽”。
admin := Admin{ User:User{ Name:"Jack", Email:"Jack@gmail.com", }, Level:"admin", } // 内部类型的方法也被提升到外部类型 admin.Speak() // 方式一 // 直接访问内部类型的方法 admin.User.Speak() // 方式二 复制代码
输出:
I am user Jack I am user Jack 复制代码
给 Admin 定义自己的 Speak() 方法:
func (a *Admin) Speak() { fmt.Println("I am admin",a.Name) } func main() { admin := Admin{ User:User{ Name:"Jack", Email:"Jack@gmail.com", }, Level:"admin", } admin.Speak() // 方式一 admin.User.Speak() // 方式二 } 复制代码
输出:
I am admin Jack I am user Jack 复制代码
可以看到,Admin 定义了自己的 Speak() 方法时,会自动调用自己的方法,而屏蔽内部类型的方法。对于属性也是一样的情况。
查看完整 代码
另外,更重要的是, 如果内部类型实现接口 A,也可以认为外部类型也实现了接口 A。
type Speaker interface { Speak() // 方法 } func gotoSpeak(s Speaker) { s.Speak() } 复制代码
定义了 Speaker 接口,任意类型如果实现了接口中定义的全部方法,就认为该类型实现了接口。例如,上面定义的 User 类型,就实现了接口 Speaker。gotoSpeak() 函数是接收 Speaker 接口类型的参数,任何实现了 Speaker 接口的类型都可以调用该函数。
admin := Admin{ User: User{ Name: "Jack", Email: "Jack@gmail.com", }, Level: "admin", } gotoSpeak(&admin) 复制代码
输出:
I am user Jack 复制代码
注意,关键点来了,调用 gotoSpeak() 时传的参数是 admin 的地址,类型是 *Admin,不能传 Admin 类型的值。从上篇文章我们知道,Admin 类型的方法集中不包括 Speak() 方法,也就是说 Admin 类型没有实现 Speaker 接口。
结合上篇关于类型方法集,对于嵌入类型的内部类型方法的提升可以总结下。假设 外部结构体类型是 S,内部类型是 T ,则关于内部类型的方法提升如下规则:
- T 嵌入 S,外部类型 S 可以通过值类型或指针类型调用内部类型 T 的值方法;
- T 嵌入 S,外部类型 S 只能通过指针类型调用内部类型 T 的指针方法;
- *T 嵌入 S,外部类型 S 可以通过值类型和指针类型调用内部类型 T 的值方法和指针方法;
上面的三条规则可以总结成一句话: 不管是 T 嵌入 S,还是 *T 嵌入 S,外部类型 S 唯独通过值类型不能调用内部类型 T 的指针方法外,其他情况下内部类型 T 的方法都可以获得提升,即可被外部类型 S 访 问 。
前两点其实很好理解,第三点是通过 指针方式组合 ,其实就是在外部类型初始化的时候,取得内部类型的指针。其他规则与非指针方式组合一致。
type Admin struct { *User // 通过指针方式组合 Level string } func main() { admin := Admin{ User: &User{ Name: "Jack", Email: "Jack@gmail.com", }, Level: "admin", } gotoSpeak(&admin) gotoSpeak(admin) } 复制代码
输出:
I am user Jack I am user Jack 复制代码
多态
其实上面的例子已经给出多态的例子了,这个给大家提一下。在 Go 语言中,每种类型都是不同的,但不同的类型可以实现同一接口,将它们绑定在同一接口上,用作函数或者放的输入(输出)参数。例如上面的 User 类型和 Admin 类型就是通过 Speaker 接口建立了关系。
深入阅读:
1. 教女朋友写方法(续)
3. Is Go An Object Oriented Language?
4.《Go 语言实战》5.4 5.5 节
(全文完)
原创文章,若需转载请注明出处!
欢迎扫码关注公众号「 Golang来啦 」或者移步 seekload.net ,查看更多精彩文章。
给你准备了学习 Go 语言相关书籍,公号后台回复【电子书】领取!
以上所述就是小编给大家介绍的《Go 面向对象式编程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 面向Python,面向对象(基础)
- 面向Python,面向对象(基础3)
- <<深入PHP面向对象、模式与实践>>读书笔记:面向对象设计和过程式编程
- 《JavaScript面向对象精要》之六:对象模式
- 《JavaScript面向对象精要》之三:理解对象
- 面向对象的程序设计之理解对象
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。