1. 類型斷言的格式
接口斷言類似於控制流中的if,但大量類型斷言出現時,應使用更高效的類型分支switch特性。
t := i.(T)
i表示接口變量(斷言對象),T表示要轉換的目標類型(指定類型),t表示轉換后的變量(指定類型接口)。此時,如果i沒有實現T,這個語句會觸發panic。因此,有以下改進寫法:
t, ok := i.(T)
如果斷言對象是指定的類型,則返回指定類型接口;如果不是指定的類型,斷言的第二個參數將返回false。
如果發生接口未實現,go將會把ok置為false,t置為T類型零值;正常實現時,ok為true。這里ok被認為是接口i是否實現類型T的結果。
把接口轉換成其他接口
鳥和豬具有不同特性,鳥可以飛,豬不能飛,但兩種動物都可以走。如果使用結構體實現鳥和豬,讓它們具備各自特性的Fly()和Walk()方法,就能讓鳥和豬各自實現了飛行者接口(Flyer)和行走者接口(Walker)。
對保存有鳥或豬實例的空接口類型interface{}變量進行類型斷言,如果斷言對象是指定的類型,則返回指定類型接口;如果不是指定的類型,斷言的第二個參數將返回false。
package main import ( "fmt" "testing" ) // 接口定義 type Flyer interface { // 定義飛行動物接口 Fly() } type Walker interface { // 定義行走動物接口 Walk() } // 接口實現 type bird struct{} // 定義飛行類型 func (b *bird) Fly() { // 實現飛行動物飛行接口 fmt.Println("bird: fly") } func (b *bird) Walk() { // 實現飛行動物行走接口 fmt.Println("bird: walk") } // 接口實現 type pig struct{} // 定義行走類型 func (p *pig) Walk() { // 實現行走動物行走接口 fmt.Println("pig: walk") } func main() { // 創建動物名到結構體實例的字典 animals := map[string]interface{}{ "bird": new(bird), // 創建出的結構體實例 "pig": new(pig), } // 遍歷字典 for name, obj := range animals { // obj為字典的值,是interface{}類型 f, isFlyer := obj.(Flyer) // 使用類型斷言獲得變量f,轉換后的類型是Flyer;isFlyer是接口類型轉換是否成功的結果 w, isWalker := obj.(Walker) // 使用類型斷言獲得變量w,轉換后的類型是Walker;isWalker是接口類型轉換是否成功的結果 fmt.Printf("name: %s isFlyer: %v isWalker: %v\n", name, isFlyer, isWalker) if isFlyer { f.Fly() // 調用接口方法 } if isWalker { w.Walk() // 調用接口方法 } } }
把接口轉換成其他類型
在go中,接口和其他類型的自由轉換,前提是接口已經實現。
把接口轉換為普通的指針類型。例如,把Walker接口轉換成*pig類型,
package main import ( "fmt" ) // 接口定義 type Flyer interface { // 定義飛行動物接口 Fly() } type Walker interface { // 定義行走動物接口 Walk() } // 接口實現 type bird struct{} // 定義飛行類型 func (b *bird) Fly() { // 實現飛行動物飛行接口 fmt.Println("bird: fly") } func (b *bird) Walk() { // 實現飛行動物行走接口 fmt.Println("bird: walk") } // 接口實現 type pig struct{} // 定義行走類型 func (p *pig) Walk() { // 實現行走動物行走接口 fmt.Println("pig: walk") } func main() { p1 := new(pig) var a Walker = p1 p2 := a.(*pig) // 把Walker接口轉換成*pig結構體指針類型 fmt.Printf("p1=%p p2=%p", p1, p2) // 格式化輸出指針類型 } // p1=0x118efd0 p2=0x118efd0 ,對比發現p1和p2指針是相同的
在上述代碼中,如果把Walker類型轉換成*
bird類型,將會報錯:在接口轉換時,main.Walker接口內部保存的是*
main.pig,而不是*
main.bird。因此,在接口轉換成其他類型時,接口內保存實例對應的類型指針,必須要轉換成相對應的類型指針。