1. 程式人生 > >Go 語言的 Type Switch 語句解析

Go 語言的 Type Switch 語句解析

講述了Go語言中 Type Swith 的用法以及獲取對應變數的一些特殊情況。

Type Switch 的基本用法

Type Switch 是 Go 語言中一種特殊的 switch 語句,它比較的是型別而不是具體的值。它判斷某個介面變數的型別,然後根據具體型別再做相應處理。注意,在 Type Switch 語句的 case 子句中不能使用fallthrough

它的用法如下。

switch x.(type) {
case Type1:
    doSomeThingWithType1()
case Type2:
    doSomeThingWithType2()
default
: doSomeDefaultThing() }

其中,x必須是一個介面型別的變數,而所有的case語句後面跟的型別必須實現了x的介面型別。

為了便於理解,我們可以結合下面這個例子來看:

package main

import (
    "fmt"
    "reflect"
)

type Animal interface {
    shout() string
}

type Dog struct {}

func (self Dog) shout() string {
    return fmt.Sprintf("wang wang")
}

type Cat struct
{} func (self Cat) shout() string { return fmt.Sprintf("miao miao") } func main() { var animal Animal = Dog{} switch animal.(type) { case Dog: fmt.Println("animal'type is Dog") case Cat: fmt.Println("animal'type is Cat") } }

在上面的例子中,CatDog型別都實現了介面Animal,所以它們可以跟在case

語句後面,判斷介面變數animal是否是對應的型別。

在Switch的語句表示式中宣告變數

如果我們不僅想要判斷某個介面變數的型別,還想要獲得其型別轉換後的值的話,我們可以在 Switch 的語句表示式中宣告一個變數來獲得這個值。

其用法如下所示:

package main

import (
    "fmt"
    "reflect"
)

type Animal interface {
    shout() string
}

type Dog struct {
    name string
}

func (self Dog) shout() string {
    return fmt.Sprintf("wang wang")
}

type Cat struct {
    name string
}

func (self Cat) shout() string {
    return fmt.Sprintf("miao miao")
}

type Tiger struct {
    name string
}

func (self Tiger) shout() string {
    return fmt.Sprintf("hou hou")
}

func main() {
    // var animal Animal = Tiger{}
    // var animal Animal  // 驗證 case nil
    // var animal Animal = Wolf{} // 驗證 default
    var animal Animal = Dog{}

    switch a := animal.(type) {
    case nil: // a的型別是 Animal
        fmt.Println("nil", a)
    case Dog, Cat: // a的型別是 Animal
        fmt.Println(a) // 輸出 {}
        // fmt.Println(a.name) 這裡會報錯,因為 Animal 型別沒有成員name
    case Tiger: // a的型別是 Tiger
        fmt.Println(a.shout(), a.name) // 這裡可以直接取出 name 成員
    default: // a的型別是 Animal
        fmt.Println("default", reflect.TypeOf(a), a)
    }
}

在上述程式碼中,我們可以看到a := animal.(type)語句隱式地為每個case子句聲明瞭一個變數a

變數a型別的判定規則如下:

  • 如果case後面跟著一個型別,那麼變數a在這個case子句中就是這個型別。例如在case Tiger子句中a的型別就是Tiger
  • 如果case後面跟著多個型別,那麼變數a的型別就是介面變數animal的型別,例如在case Dog, Cat子句中a的型別就是Animal
  • 如果case後面跟著nil,那麼變數a的型別就是介面變數animal的型別Animal,通常這種子句用來判斷未賦值的介面變數
  • default子句中變數a的型別是介面變數animal的型別

為了更好地理解上述規則,我們可以用if語句和型別斷言來重寫這個switch語句,如下所示:

    v := animal   // animal 只會被求值一次
    if v == nil { // case nil 子句
        a := v
        fmt.Println("nil", a)
    } else if a, isTiger := v.(Tiger); isTiger { // case Tiger 子句
        fmt.Println(a.shout(), a.name)
    } else {
        _, isDog := v.(Dog)
        _, isCat := v.(Cat)
        if isDog || isCat { // case Dog, Cat 子句
            a := v
            fmt.Println(a)
            // fmt.Println(a.name)
        } else { // default 子句
            a := v
            fmt.Println("default", reflect.TypeOf(a), a)
        }
    }

參考連結