golang類型斷言(Type Assertion)的應用

簡單記錄下平時開發對類型斷言(Type Assertion)的使用場景。golang

golang裏的全部類型都實現了空接口interface{},因此一般將它做爲一個函數的參數或者結構體的字段,以實現對類型的抽象。函數

1.用於轉換函數裏interface{}類型的參數
舉個簡單栗子:code

package main

import "fmt"

func main() {
    add(1, 2)
    add(int16(1), int16(2))
    add(float32(1.1), float32(2.2))
    add(float64(1.1), float64(2.2))
    add(true, false)
}

func add(a, b interface{}) {
    switch t := a.(type) {
    case int:
        fmt.Printf("type [%T] add res[%d]\n", t, a.(int)+b.(int))
    case int16:
        fmt.Printf("type [%T] add res[%d]\n", t, a.(int16)+b.(int16))
    case float32:
        fmt.Printf("type [%T] add res[%f]\n", t, a.(float32)+b.(float32))
    case float64:
        fmt.Printf("type [%T] add res[%f]\n", t, a.(float64)+b.(float64))
    default:
        fmt.Printf("type [%T] not support!\n", t)
    }
}

輸出結果:接口

type [int] add res[3]
type [int16] add res[3]
type [float32] add res[3.300000]
type [float64] add res[3.300000]
type [bool] not support!開發

用interface{}做參數,是否是很像C++的模板函數,而類型斷言是否是很像C++的類層次間的下行轉換(也是不必定成功的)。須要注意的是,a.(type)只能和switch搭配使用。在使用前得用斷言指明變量的類型,若是斷言錯誤就會觸發panic。string

若是不想觸發panic,先作判斷再使用。it

package main

import "fmt"

func main() {
    a := int16(2)
    b := int32(3)
    add(a, b)
}

func add(a, b interface{}) {
    _, ok := a.(int32)
    if !ok {
        fmt.Println("error type assertion!")
    }
    b = b
}

運行結果:
error type assertion!
2.用於轉換結構體的interface{}類型字段
例如,咱們寫handler去接收消息,不可能每一個發來的消息都寫個函數去handle。利用空接口和類型斷言的特性,就能夠將業務抽象出來:io

package main
    
    import "fmt"
    import "time"
    
    type NetMsg struct {
        MsgID int16
        Data  interface{}
    }
    
    type Cat struct {
        name string
        age  int16
    }
    
    type Dog struct {
        name string
        age  int32
    }
    
    type human struct {
        name string
        age  int64
    }
    
    func main() {
        msg1 := NetMsg{1, Cat{"Qian", 1}}
        msg2 := NetMsg{2, Dog{"doge", 8}}
        msg3 := NetMsg{3, Dog{"allu", 18}}
        msg_handler(msg1)
        time.Sleep(2000 * time.Millisecond)
        msg_handler(msg2)
        time.Sleep(2000 * time.Millisecond)
        msg_handler(msg3)
    }
    
    func msg_handler(msg NetMsg) {
        switch msg.MsgID {
        case 1:
            cat := msg.Data.(Cat)
            fmt.Printf("Do Something with Msg 1 %v \n", cat)
        case 2:
            dog := msg.Data.(Dog)
            fmt.Printf("Do Something with Msg 2 %v \n", dog)
        default:
            fmt.Printf("Error MsgID [%d] \n", msg.MsgID)
        }
    }

運行結果:
Do Something with Msg 1 {Qian 1}
Do Something with Msg 2 {doge 8}
Error MsgID [3]模板

相關文章
相關標籤/搜索