Go 語言的 Type Switch 語句解析
阿新 • • 發佈:2019-02-12
講述了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")
}
}
在上面的例子中,Cat
和Dog
型別都實現了介面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)
}
}