golang中没有继承的概念,代码复用是通过组合的方式实现。本文简单介绍golang中组合的使用方法和一些细节。直接先上代码:
package main
import "fmt"
type Person struct {
Name string
}
func (p *Person) PrintName() {
fmt.Println("I am a person, ", p.Name)
}
type Teacher struct {
Person
Title string
}
func (t *Teacher) PrintInfo() {
info := fmt.Sprintf("I am a teacher, my name is %s, my title is %s", t.Name, t.Title)
fmt.Println(info)
}
func main() {
t := &Teacher{Title: "Director", Person: Person{"Bob"}}
t.PrintInfo()
t.PrintName()
}
Teacher中组合了Person,首先需要注意的是Teacher的初始化方式:
t := &Teacher{Title: "Director", Person: Person{"Bob"}}
其次,Teacher对象可以调用Person的方法和成员变量:
t.Name
t.PrintName()
上述例子输出:
I am a teacher, my name is Bob, my title is Director
I am a person, Bob
如果Teacher中包含的是一个Person对象,而不是组合Person,那又会怎样呢?
package main
import "fmt"
type Person struct {
Name string
}
func (p *Person) PrintName() {
fmt.Println("I am a person, ", p.Name)
}
type Teacher struct {
//此处包含一个Person对象
p Person
Title string
}
func (t *Teacher) PrintInfo() {
info := fmt.Sprintf("I am a teacher, my name is %s, my title is %s", t.p.Name, t.Title)
fmt.Println(info)
}
func main() {
t := &Teacher{Title: "Director", p: Person{"Bob"}}
t.PrintInfo()
t.p.PrintName()
}
此时p作为Teacher的成员变量,Teacher的初始化方式有很大不同,同时调用Person函数的方法也需要p对象来调用。
那么如果将Person实现为interface,Teacher实现该interface, 也能实现代码模块化和某种规则约定, 如下代码:
package main
import "fmt"
type Person interface {
PrintName()
}
type Teacher struct {
Title string
Name string
}
func PrintInfo(t Person) {
info := fmt.Sprintf("I am a teacher, my name is %s, my title is %s", t.(Teacher).Name, t.(Teacher).Title)
fmt.Println(info)
}
func (t Teacher) PrintName() {
fmt.Println("My name is ", t.Name)
}
func main() {
t := Teacher{Title: "Director", Name: "Bob"}
PrintInfo(t)
}
输出:
I am a teacher, my name is Bob, my title is Director
这里PrintName为接口约定的函数,凡是实现了该函数的struct就认为实现了该接口。如果将PrintName的接收者参数改为指针形式呢?
package main
import "fmt"
type Person interface {
PrintName()
}
type Teacher struct {
Title string
Name string
}
func PrintInfo(t Person) {
info := fmt.Sprintf("I am a teacher, my name is %s, my title is %s", t.(*Teacher).Name, t.(*Teacher).Title)
fmt.Println(info)
}
func (t *Teacher) PrintName() {
fmt.Println("My name is ", t.Name)
}
func main() {
t := Teacher{Title: "Director", Name: "Bob"}
PrintInfo(&t)
}
改为指针接收者以后,即认为指针类型实现了该接口,因此传递给PrintInfo的参数也必须是指针类型,因为非指针类型并没有实现接口,类型不匹配。会报如下的错误:
cannot use t (variable of type Teacher) as Person value in argument to
PrintInfo: missing method PrintName (PrintName has pointer receiver)