Go
语言并没有设计诸如虚函数、纯虚函数、继承、多重继承等概念,但它通过接口却非常优雅地支持了面向对象的特性。
多态是一种运行期的行为,它有以下几个特点:
看一个实现了多态的代码例子:
packagemain
import"fmt"
funcmain(){
qcrao:=Student{age:18}
whatJob(&qcrao)
growUp(&qcrao)
fmt.Println(qcrao)
stefno:=Programmer{age:100}
whatJob(stefno)
growUp(stefno)
fmt.Println(stefno)
}
funcwhatJob(pPerson){
p.job()
}
funcgrowUp(pPerson){
p.growUp()
}
typePersoninterface{
job()
growUp()
}
typeStudentstruct{
ageint
}
func(pStudent)job(){
fmt.Println("Iamastudent.")
return
}
func(p*Student)growUp(){
p.age+=1
return
}
typeProgrammerstruct{
ageint
}
func(pProgrammer)job(){
fmt.Println("Iamaprogrammer.")
return
}
func(pProgrammer)growUp(){
//程序员老得太快^_^
p.age+=10
return
}
代码里先定义了1个Person
接口,包含两个函数:
job()
growUp()
然后,又定义了2个结构体,Student
和Programmer
,同时,类型*Student
、Programmer
实现了Person
接口定义的两个函数。注意,*Student
类型实现了接口,Student
类型却没有。
之后,我又定义了函数参数是Person
接口的两个函数:
funcwhatJob(pPerson)
funcgrowUp(pPerson)
main
函数里先生成Student
和Programmer
的对象,再将它们分别传入到函数whatJob
和growUp
。函数中,直接调用接口函数,实际执行的时候是看最终传入的实体类型是什么,调用的是实体类型实现的函数。于是,不同对象针对同一消息就有多种表现,多态
就实现了。
更深入一点来说的话,在函数whatJob()
或者growUp()
内部,接口person
绑定了实体类型*Student
或者Programmer
。根据前面分析的iface
源码,这里会直接调用fun
里保存的函数,类似于:s.tab->fun[0]
,而因为fun
数组里保存的是实体类型实现的函数,所以当函数传入不同的实体类型时,调用的实际上是不同的函数实现,从而实现多态。
运行一下代码:
Iamastudent.
{19}
Iamaprogrammer.
{100}
本文节选于Go合集《常见面试题汇总》:GOLANG ROADMAP 一个专注Go语言学习、求职的社区。