在聊通用万能类型 interface{} 接口之前,先来谈谈 Golang 中多态的实现与基本要素。
interface 定义抽象方法,子类继承并且实现对应的抽象方法,以达到一个抽象接口有多个不同表现形式的目的,这种现象被称为面向对象的多态。
当我们继承一个类时,需要在 struct 中将父类的名字写下来,如果继承接口的话,则无需将父类的名字写下来,直接将接口包含的抽象方法全部实现即可,此时我们可以直接使用 interface 指针接收(指向)一个子对象。
package mainimport "fmt"
// 本质是一个指针
type AnimalIF interface {
Sleep()
GetColor() string // 获取动物的颜色
GetType() string // 获取动物的种类
}
// 具体的类
type Cat struct {
color string // 猫的颜色
}
func (this *Cat) Sleep() {
fmt.Println("Cat is Sleep...")
}
func (this *Cat) GetColor() string {
return this.color
}
func (this *Cat) GetType() string {
return "Cat"
}
type Dog struct {
color string
}
func (this *Dog) Sleep() {
fmt.Println("Dog is Sleep...")
}
func (this *Dog) GetColor() string {
return this.color
}
func (this *Dog) GetType() string {
return "Dog"
}
func showAnimal(animal AnimalIF) {
animal.Sleep() // 多态
fmt.Println("color = ", animal.GetColor())
fmt.Println("kind = ", animal.GetType())
}
func main() {
var animal AnimalIF // 接口的数据类型,父类指针
animal = &Cat{"Green"}
animal.Sleep() // 调用的就是 Cat 的 Sleep() 方法
animal = &Dog{"Yellow"}
animal.Sleep() // 调用 Dog 的 Sleep() 方法,多态现象
cat := Cat{"Green"}
dog := Dog{"Yellow"}
showAnimal(&cat)
showAnimal(&dog)
}
go fmt .\main.go
go run .\main.go
通用万能类型 interface{},就是元类,表示空接口,就是所有的 struct 最终都实现了这个空接口。
如 int、string、float32、float64、struct 都实现了 interface{} 空接口,可以使用 interface{} 数据类型引用任意数据类型。
package mainimport "fmt"
func myFunc(arg interface{}) {
fmt.Println("myFunc() is called...")
fmt.Println(arg)
}
type Book struct {
auth string
}
func main() {
book := Book{"Golang"}
myFunc(book)
myFunc(233)
myFunc("tonghuaroot")
myFunc(3.14)
}
通过类型断言机制,interface{} 可以区分引用的底层数据类型。
package mainimport "fmt"
func myFunc(arg interface{}) {
fmt.Println("myFunc() is called...")
fmt.Println(arg)
value, ok := arg.(string)
if !ok {
fmt.Println("==========")
fmt.Println("arg is not string type")
fmt.Println("value = ", value)
fmt.Printf("value type is %T \n", value) // 在类型断言机制中,如果 arg 不是 string 类型,则 value 值为一个 string 类型的空值(其他类型也适用)
fmt.Println("==========")
} else {
fmt.Println("arg is string type, value = ", value)
fmt.Printf("value type is %T \n", value)
}
}
type Book struct {
auth string
}
func main() {
book := Book{"Golang"}
myFunc(book)
myFunc(233)
myFunc("tonghuaroot")
myFunc(3.14)
}
父类的方法通常也包含了一些功能,子类可以重写父类的方法实现新的功能,接口均为抽象方法,是没有实现的空方法,子类实现该接口时要为这些方法定义对应的功能。如果我们有多态的需求,比如说在调用函数时,形式参数传入接口对象,此时可以依据需求传入不同的子类引用,进而执行不同的功能,这种场景是推荐使用接口与子类这种继承(实现)的,其他情况可以采用父类与子类继承这种模式。
算。
package mainimport "fmt"
// 本质是一个指针
type AnimalIF interface {
Sleep()
GetColor() string // 获取动物的颜色
GetType() string // 获取动物的种类
}
// 具体的类
type Cat struct {
color string // 猫的颜色
}
func (this *Cat) Sleep() {
fmt.Println("Cat is Sleep...")
}
func (this *Cat) GetColor() string {
return this.color
}
func (this *Cat) GetType() string {
return "Cat"
}
type Dog struct {
color string
}
func (this *Dog) Sleep() {
fmt.Println("Dog is Sleep...")
}
func (this *Dog) GetColor() string {
return this.color
}
func (this *Dog) GetType() string {
return "Dog"
}
func (this *Dog) PrintMsg() string {
return "Hmm..."
}
func showAnimal(animal AnimalIF) {
animal.Sleep() // 多态
fmt.Println("color = ", animal.GetColor())
fmt.Println("kind = ", animal.GetType())
}
func main() {
var animal AnimalIF // 接口的数据类型,父类指针
animal = &Cat{"Green"}
animal.Sleep() // 调用的就是 Cat 的 Sleep() 方法
animal = &Dog{"Yellow"}
animal.Sleep() // 调用 Dog 的 Sleep() 方法,多态现象
cat := Cat{"Green"}
dog := Dog{"Yellow"}
fmt.Println("Dog Print Message: ", dog.PrintMsg())
showAnimal(&cat)
showAnimal(&dog)
}