這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
經常地我們對一個介面值的動態類型是不確定的,如方法的形參為介面類型時,此時就需要檢驗它是否符合我們需要的類型。
類型斷言是一個使用在介面值上的操作。
如果對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 Testert = 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