共计 3801 个字符,预计需要花费 10 分钟才能阅读完成。
【Go 语言入门系列】后面的文章:
- 【Go 语言入门系列】(五)指针和构造体的应用
- 【Go 语言入门系列】(六)再探函数
- 【Go 语言入门系列】(七)如何应用 Go 的办法?
1. Go 是面向对象的语言吗?
在【Go 语言入门系列】(七)如何应用 Go 的办法?这一文中曾经介绍了办法的概念,但这个办法实际上并不是面向对象中的办法。办法实际上是用户给其定义的类型的减少的新行为,实际上也是个函数。
对于这个问题,官网文档中有答复:
Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy. The concept of“interface”in Go provides a different approach that we believe is easy to use and in some ways more general. There are also ways to embed types in other types to provide something analogous—but not identical—to subclassing. Moreover, methods in Go are more general than in C++ or Java: they can be defined for any sort of data, even built-in types such as plain,“unboxed”integers. They are not restricted to structs (classes).
Also, the lack of a type hierarchy makes“objects”in Go feel much more lightweight than in languages such as C++ or Java.
既是也不是。只管 Go 领有类型和办法,也容许面向对象格调的编程,但它没有类型层级。在 Go 中“接口”的概念提供了不同的办法,咱们置信它易于应用且在某些方面更通用。也有一些在其它类型中嵌入类型的办法,来提供相似(而非完全相同)的货色进行子类化。此外,Go 中的办法比 C ++ 或 Java 中的更通用:它们可被定义为任何品种的数据。甚至是像一般的“未装箱”整数这样的内建类型。它们并不受构造(类)的限度。
此外,类型层级的缺失也使 Go 中的“对象”感觉起来比 C ++ 或 Java 的更轻量级。
有了这个答复,上面介绍的“继承”和“重写”的概念并不是严格的面向对象中的继承和重写的概念。这里只借用这两个名词来示意 Go 的两种个性。
2.“继承”
在面向对象中,继承是子类和父类之间的关系,子类会继承父类的私有成员变量和成员办法。
后面提到过,Go 容许面向对象格调的编程。那 Go 如何“继承”呢?
2.1.“继承”字段
在【Go 语言入门系列】(五)指针和构造体的应用这一文中,介绍了匿名字段(也叫嵌入字段):
package main
import "fmt"
type people struct {
name string
age int
}
type student struct {
people
school string
}
func (s student) say() {fmt.Printf("我是 %s,往年 %d 岁了,在 %s 上学。", s.name, s.age, s.school)
}
func main() {stu := student{people{"行小观", 1}, "阳光小学"}
stu.say()}
运行:
我是行小观, 往年 1 岁了, 在阳光小学上学
构造体 student
中有匿名字段 people
,所以student
就有了 people
的name
和 age
字段。当匿名字段是一个构造体时,那么该构造体的全副字段都会被引入以后的构造体中。这是不是很像面向对象中的继承?子类继承父类的私有成员变量。
思考上面一个问题,如果 student
和people
中都有 name
字段,那么拜访时,Go 语言是如何解决的?
package main
import "fmt"
type people struct {
name string // 人名
age int
}
type student struct {
people
name string // 学生名
school string
}
func main() {stu := student{people{"李二狗", 1}, "李向前", "阳光学校"}
fmt.Println(stu.name) // 李向前
fmt.Println(stu.people.name) // 李二狗
}
此时就呈现了字段抵触,Go 会先拜访外层的字段。比方,stu.name
是 李向前
(外层),stu.people.name
是李二狗
(内层)。
2.2.“继承”办法
咱们通过接收者把函数绑定到构造体类型上,这样的函数称为办法,办法就在概念上属于了接收者对应的构造体。
下面通过构造体中匿名字段实现了“继承”字段的成果,对于办法来说,同样能够。上面是一个实例:
package main
import "fmt"
type people struct {
name string
age int
}
type student struct {
people
school string
}
type programmer struct {
people
language string
}
func (p people) say() {fmt.Printf("我是 %s,往年 %d 岁了,和我一起学习 Go 语言吧!\n", p.name, p.age)
}
func main() {stu := student{people{"行小观", 1}, "阳光小学"}
stu.say()
prom := programmer{people{"张三", 1}, "蓝天修建有限公司"}
prom.say()}
运行:
我是行小观,往年 1 岁了,和我一起学习 Go 语言吧!我是张三,往年 1 岁了,和我一起学习 Go 语言吧!
say()
办法的接收者是 people
类型,而构造体 student
和programmer
中都有匿名字段 people
,所以stu
和prom
都能调用 say()
办法。这是不是很像面向对象语言中子类继承父类的私有办法?
3.“重写”
3.1.“重写”字段
后面曾经介绍了如果构造体和作为其字段的构造体的字段抵触了如何解决。有了这个个性,咱们就能够“重写”字段。
package main
import "fmt"
type people struct {
name string // 乳名
age int
}
type student struct {
people
name string // 小名
school string
}
func (s student) say() {fmt.Printf("我是 %s,往年 %d 岁了,和我一起学习 Go 语言吧!\n", s.name, s.age)
}
func main() {stu := student{people{"李二狗", 1}, "李向前","阳光小学"}
stu.say()}
运行:
我是李向前,往年 1 岁了,和我一起学习 Go 语言吧!
李二狗是乳名,李向前才是小名。自我介绍时说的是小名李向前。如果须要乳名,则应用stu.people.name
。
3.2.“重写”办法
上面是一个实例:
package main
import "fmt"
type people struct {
name string
age int
}
type student struct {
people
school string
}
type programmer struct {
people
language string
}
func (p people) say() { //people 的 say 办法
fmt.Printf("我是 %s,往年 %d 岁了,和我一起学习 Go 语言吧!\n", p.name, p.age)
}
func (s student) say() { //student 重写 people 的 say 办法
fmt.Printf("我是 %s,是个学生,往年 %d 岁了,我在 %s 上学!\n", s.name, s.age, s.school)
}
func (p programmer) say() { //programmer 重写 people 的 say 办法
fmt.Printf("我是 %s,是个程序员,往年 %d 岁了,我应用 %s 语言!\n", p.name, p.age, p.language)
}
func main() {stu := student{people{"李向前", 1}, "阳光小学"}
stu.say()
prmger := programmer{people{"张三", 1}, "Go"}
prmger.say()}
运行:
我是李向前,是个学生,往年 1 岁了,我在阳光小学上学!我是张三,是个程序员,往年 1 岁了,我应用 Go 语言!
student
和 programmer
“继承”了people
的say()
办法,然而不适合,于是各自“重写”了 say()
办法。
看到这里,你就了解了官网文档中的那两句话是什么意思了。
“只管 Go 领有类型和办法,也容许面向对象格调的编程,但它没有类型层级”
“类型层级的缺失也使 Go 中的“对象”感觉起来比 C ++ 或 Java 的更轻量级”
作者简介
我是行小观,我会在公众号『行人观学』中继续更新 Java、Go、数据结构和算法、计算机根底等相干文章。
本文章收录于系列文章「Go 语言入门系列」,本系列从 Go 语言根底开始介绍,适宜从零开始的初学者。
欢送关注,咱们一起踏上编程的行程。
如有谬误,还请斧正。