經常地我們對一個接口值的動態類型是不確定的,如方法的形參為接口類型時,此時就需要檢驗它是否符合我們需要的類型。
類型斷言是一個使用在接口值上的操作。
如果對Golang的接口和接口值的概念不熟悉,看這里:Go的接口總結
斷言類型的語法:x.(T),這里x表示一個接口的類型,T表示一個類型(也可為接口類型)。
一個類型斷言檢查一個接口對象x的動態類型是否和斷言的類型T匹配。
類型斷言分兩種情況:
第一種,如果斷言的類型T是一個具體類型,類型斷言x.(T)就檢查x的動態類型是否和T的類型相同。
- 如果這個檢查成功了,類型斷言的結果是一個類型為T的對象,該對象的值為接口變量x的動態值。換句話說,具體類型的類型斷言從它的操作對象中獲得具體的值。
- 如果檢查失敗,接下來這個操作會拋出panic,除非用兩個變量來接收檢查結果,如:f, ok := w.(*os.File)
第二種,如果斷言的類型T是一個接口類型,類型斷言x.(T)檢查x的動態類型是否滿足T接口。
- 如果這個檢查成功,則檢查結果的接口值的動態類型和動態值不變,但是該接口值的類型被轉換為接口類型T。換句話說,對一個接口類型的類型斷言改變了類型的表述方式,改變了可以獲取的方法集合(通常更大),但是它保護了接口值內部的動態類型和值的部分。
- 如果檢查失敗,接下來這個操作會拋出panic,除非用兩個變量來接收檢查結果,如:f, ok := w.(io.ReadWriter)
注意:
- 如果斷言的操作對象x是一個nil接口值,那么不論被斷言的類型T是什么這個類型斷言都會失敗。
- 我們幾乎不需要對一個更少限制性的接口類型(更少的方法集合)做斷言,因為它表現的就像賦值操作一樣,除了對於nil接口值的情況。
示例代碼:
//===接口===== type Tester interface { getName()string } type Tester2 interface { printName() } //===Person類型==== type Person struct { name string } func (p Person)getName() string { return p.name } func (p Person) printName() { fmt.Println(p.name) } //============ func main() { var t Tester t = Person{"xiaohua"} check(t) } func check(t Tester) { //第一種情況 if f, ok1 := t.(Person);ok1 { fmt.Printf("%T\n%s\n",f,f.getName()) } //第二種情況 if t, ok2 := t.(Tester2);ok2 { //重用變量名t(無需重新聲明) check2(t) //若類型斷言為true,則新的t被轉型為Tester2接口類型,但其動態類型和動態值不變 } } func check2(t Tester2) { t.printName() }
執行結果:
main.Person
xiaohua
xiaohua