1. 基本实现
Golang并非设计成了一种面向对象的语言,没有Class的概念,因此在继承和多态的实现上有些让人难以快速理解的地方。
首先看继承的实现,以经典的学生-小学生-大学生为例:
代码语言:go复制type Student struct {
Name string //姓名
Age int //年龄
Score int //成绩
}
type Pupil struct {
Student
}
type Graduate struct {
Student
}
这样就实现了继承。因为Pupil和Graduate都能够使用到父类(父结构体)。
实现了继承,就可以实现多态,一般的多态可以用这样的类图来表示:
对于Java来说实现起来很简单,如果利用Golang的interface,实现起来也不是很难:
代码语言:go复制package person
import "fmt"
type Student struct {
Name string //姓名
Age int //年龄
Score int //成绩
}
type Pupil struct {
Student
}
type Graduate struct {
Student
}
type Study interface {
Exam()
}
func (t *Pupil) Exam() {
fmt.Printf("小学生%s在考试n", t.Name)
}
func (t *Graduate) Exam() {
fmt.Printf("大学生%s在考试n", t.Name)
}
这样Pupil和Graduate都实现了Study接口,用main函数调用:
代码语言:go复制func main() {
s := &person.Pupil{}
s.Student.Name = "zhiquan"
s.Student.Age = 12
s.Student.Score = 100
s.Exam()
g := &person.Graduate{}
g.Student.Name = "Lee"
g.Student.Age = 22
g.Student.Score = 85
g.Exam()
}
从另一个角度来说,这实际上确实实现了多态。同一种父类下不同的实现,实现了不同的方法。
如果说struct对应Java里的Class的话,那么就比较好理解了,实际上就是Struct实现了接口,只不过接口里定义的行为没办法在Struct里实现,只能在其他地方实现。
2. 函数的显式类型转换
“函数是一等公民”这个说法是Golang领域的一个重要概念,所谓的“一等公民”,我现在的理解,那无非是函数可以像一个基本类型一样使用,比如当做参数来传递,也可以当做一种类型来使用。
这种代码在Go的世界里是会报错的:
代码语言:go复制var a int = 3
var b int32 = 5
fmt.Println(a b)
就是类型不匹配,因此需要转换一下子:
代码语言:go复制var a int = 3
var b int32 = 5
fmt.Println(a int(b))
在《Go语言精进之路》这本书里,提到了一个概念叫做:函数是一等公民。
就是说函数在Go中很重要,很灵活,可以像一个变量一样使用。
比如下面这段代码:
代码语言:go复制package main
import "fmt"
type BinaryAdder interface {
Add(int, int) int
}
type MyAdderFunc func(int, int) int
func (f MyAdderFunc) Add(x, y int) int {
return f(x, y)
}
func MyAdd(x, y int) int {
return x y
}
func main() {
var i BinaryAdder = MyAdderFunc(MyAdd)
fmt.Println(i.Add(1, 2))
}
在20行的地方进行了一次显式的类型转换,将MyAdd转换成了MyAdderFunc类型,而MyAdderFunc实现了BinaryAdder接口,因此可以完成20行的赋值语句。
这就是一种多态的实现,继承了BinaryAdder接口的类MyAdderFunc是可以向上转型的。和之前的多态例子不谋而合。