Golang中的多态与类型断言
多态简介
变量(实例)具有多种形态。面向对象的第三大特征。在Go语言,多态特征是通过接口实现的。可以按照统一的接口来调用不同的实现。这时接口变量就呈现不同的形态
只要自定义数据类型实现了接口的所有方法,就是隐式实现了接口,那么接口就可以引用实现了接口的变量
多态的实现方式
①多态参数
package main
import "fmt"
type Usb interface {
Connection()
Startworking()
Stopworking()
Disconnection()
}
type Mobile struct {
}
type Camera struct {
}
type Computer struct {
}
func (mob *Mobile) Connection() {
fmt.Println("Mobile Connection done")
}
func (mob *Mobile) Startworking() {
fmt.Println("Mobile Startworking")
}
func (mob *Mobile) Stopworking() {
fmt.Println("Mobile Stopworking")
}
func (mob *Mobile) Disconnection() {
fmt.Println("Mobile Disconnection done")
}
func (cam *Camera) Connection() {
fmt.Println("Camera Connection done")
}
func (cam *Camera) Startworking() {
fmt.Println("Camera Startworking")
}
func (cam *Camera) Stopworking() {
fmt.Println("Camera Stopworking")
}
func (cam *Camera) Disconnection() {
fmt.Println("Camera Disconnection done")
}
func (comp *Computer) UsbWorking(usb Usb) {
usb.Connection()
usb.Startworking()
usb.Stopworking()
usb.Disconnection()
}
func main() {
cam := Camera{}
mob := Mobile{}
comp := &Computer{}
comp.UsbWorking(&cam)
comp.UsbWorking(&mob)
}
输出的是
Camera Connection done
Camera Startworking
Camera Stopworking
Camera Disconnection done
Mobile Connection done
Mobile Startworking
Mobile Stopworking
Mobile Disconnection done这里下面的代码,usb Usb就体现的是多态
func (comp *Computer) UsbWorking(usb Usb) {
usb.Connection()
usb.Startworking()
usb.Stopworking()
usb.Disconnection()
}
usb可以引用Camera或者Mobile类型的结构体
②多态数组
在Usb数组中,可以存放Phone结构体变量和Camera结构体变量
func main() {
var usbArr [3]Usb
usbArr[0] = Phone{}
usbArr[1] = Phone{}
usbArr[2] = Camera{}
}
像这样是可以的
类型断言
在多态数组的实现中,我们用Usb数组存放Phone结构体变量和Camera结构体变量,Phone还有一个特有的方法call(),请遍历Usb数组,如果是Phone变量,除了调用Usb接口声明的方法外,还需要调用Phone特有方法call
我们将根据这个案例来引出类型断言
如果我们直接调用usb.call()一定会出问题,因为usb可能引用的是Camera结构体变量,我们知道,Camera结构体变量是没有call()方法的
因此需要类型断言判断它到底是Camera还是Mobile
package main
import "fmt"
type Point struct {
x int
y int
}
func main() {
var a interface{} //声明一个空接口
var point Point = Point{1, 2}
a = point
var b Point
b = a //这个地方会报错
fmt.Println("The value of b is", b)
}
我们来看报的错是:
cannot use a (variable of type interface{}) as Point value in assignment: need type assertion compiler Incompatible Assigna是空接口类型,不能赋给b,这里需要一个类型assertion(断言)
b = a.(Point)
这个就是断言,a这个空接口看是否能转换成Point,如果能转换,就转换后赋给b,如果不能就报错
注意这个作断言的时候类型一定要匹配
package main
import "fmt"
func main() {
var a interface{}
var b float32 = 1.1
var c float64
a = b
c = a.(float64) //这样是一定会报错的
fmt.Println(c)
}
报错的内容如下
panic: interface conversion: interface {} is float32, not float64类型不匹配
类型断言带检测
package main
import "fmt"
func main() {
var a interface{}
var b float32 = 1.1
var c float64
a = b
c, ok = a.(float64) //这样是一定会报错的
if ok == true {
fmt.Println("convert success")
fmt.Printf("y的类型是 %T 值是=%v", y, y)
} else {
fmt.Println("convert fail")
}
fmt.Println("继续执行...")
}
输出的是
convert success
y的类型是 float32 值是=1.1
继续执行...如果转换成功ok就是true,如果失败ok就是false
类型断言的实践
比如传入多个变量,判断它们的类型,代码如下
package main
import "fmt"
func TypeJudge(items ...interface{}) {
for index, value := range items {
switch value.(type) {
case bool:
fmt.Printf("The number %d value's type is:%T\n", index, value)
case int:
fmt.Printf("The number %d value's type is:%T\n", index, value)
case float32:
fmt.Printf("The number %d value's type is:%T\n", index, value)
case float64:
fmt.Printf("The number %d value's type is:%T\n", index, value)
case nil:
fmt.Printf("The number %d value's type is:%T\n", index, value)
case string:
fmt.Printf("The number %d value's type is:%T\n", index, value)
default:
fmt.Printf("Default: The number %d value's type is:%T\n", index, value)
}
}
}
func main() {
TypeJudge(1, float32(1.3), float64(3.4), "zideng", nil, int64(23))
}
输出的是
The number 0 value's type is:int
The number 1 value's type is:float32
The number 2 value's type is:float64
The number 3 value's type is:string
The number 4 value's type is:<nil>
Default: The number 5 value's type is:int64这个value.(type)用法会返回空指针引用的变量的类型