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 Assign

a是空接口类型,不能赋给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)用法会返回空指针引用的变量的类型