天天看點

14. Go 語言中的類型斷言是什麼?

Hi,大家好,我是明哥。

在自己學習 Golang 的這段時間裡,我寫了詳細的學習筆記放在我的個人微信公衆号 《Go程式設計時光》,對于 Go 語言,我也算是個初學者,是以寫的東西應該會比較适合剛接觸的同學,如果你也是剛學習 Go 語言,不防關注一下,一起學習,一起成長。

我的線上部落格:http://golang.iswbm.com 我的 Github:github.com/iswbm/GolangCodingTime

Type Assertion

Type Assertion(中文名叫:類型斷言),通過它可以做到以下幾件事情

  1. 檢查

    i

    是否為 nil
  2. 檢查

    i

    存儲的值是否為某個類型

具體的使用方式有兩種:

第一種:

t := i.(T)
           

這個表達式可以斷言一個接口對象(i)裡不是 nil,并且接口對象(i)存儲的值的類型是 T,如果斷言成功,就會傳回值給 t,如果斷言失敗,就會觸發 panic。

來寫段代碼試驗一下

package main

import "fmt"

func main() {
    var i interface{} = 10
    t1 := i.(int)
    fmt.Println(t1)

    fmt.Println("=====分隔線=====")

    t2 := i.(string)
    fmt.Println(t2)
}
           

運作後輸出如下,可以發現在執行第二次斷言的時候失敗了,并且觸發了 panic

10
=====分隔線=====
panic: interface conversion: interface {} is int, not string

goroutine 1 [running]:
main.main()
        E:/GoPlayer/src/main.go:12 +0x10e
exit status 2
           

如果要斷言的接口值是 nil,那我們來看看也是不是也如預期一樣會觸發panic

package main

func main() {
    var i interface{} // nil
    var _ = i.(interface{})
}
           

輸出如下,确實是會 觸發 panic

panic: interface conversion: interface is nil, not interface {}

goroutine 1 [running]:
main.main()
        E:/GoPlayer/src/main.go:5 +0x34
exit status 2
           

第二種

t, ok:= i.(T)
           

和上面一樣,這個表達式也是可以斷言一個接口對象(i)裡不是 nil,并且接口對象(i)存儲的值的類型是 T,如果斷言成功,就會傳回其類型給 t,并且此時 ok 的值 為 true,表示斷言成功。

如果接口值的類型,并不是我們所斷言的 T,就會斷言失敗,但和第一種表達式不同的事,這個不會觸發 panic,而是将 ok 的值設為 false ,表示斷言失敗,此時t 為 T 的零值。

稍微修改下上面的例子,如下

package main

import "fmt"

func main() {
    var i interface{} = 10
    t1, ok := i.(int)
    fmt.Printf("%d-%t\n", t1, ok)

    fmt.Println("=====分隔線1=====")

    t2, ok := i.(string)
    fmt.Printf("%s-%t\n", t2, ok)

    fmt.Println("=====分隔線2=====")

    var k interface{} // nil
    t3, ok := k.(interface{})
    fmt.Println(t3, "-", ok)

    fmt.Println("=====分隔線3=====")
    k = 10
    t4, ok := k.(interface{})
    fmt.Printf("%d-%t\n", t4, ok)

    t5, ok := k.(int)
    fmt.Printf("%d-%t\n", t5, ok)
}
           

運作後輸出如下,可以發現在執行第二次斷言的時候,雖然失敗了,但并沒有觸發了 panic。

10-true
=====分隔線1=====
-false
=====分隔線2=====
<nil> - false
=====分隔線3=====
10-true
10-true
           

上面這段輸出,你要注意的是第二個斷言的輸出在

-false

之前并不是有沒有輸出任何 t2 的值,而是由于斷言失敗,是以 t2 得到的是 string 的零值也是

""

,它是零長度的,是以你看不到其輸出。

Type Switch

如果需要區分多種類型,可以使用 type switch 斷言,這個将會比一個一個進行類型斷言更簡單、直接、高效。

package main

import "fmt"

func findType(i interface{}) {
    switch x := i.(type) {
    case int:
        fmt.Println(x, "is int")
    case string:
        fmt.Println(x, "is string")
    case nil:
        fmt.Println(x, "is nil")
    default:
        fmt.Println(x, "not type matched")
    }
}

func main() {
    findType(10)      // int
    findType("hello") // string

    var k interface{} // nil
    findType(k)

    findType(10.23) //float64
}
           

輸出如下

10 is int
hello is string
<nil> is nil
10.23 not type matched
           

額外說明一下:

  • 如果你的值是 nil,那麼比對的是

    case nil

  • 如果你的值在 switch-case 裡并沒有比對對應的類型,那麼走的是 default 分支

參考文章

  • Explain Type Assertions in Go
  • Go interface 詳解 (四) :類型斷言

系列導讀

01. 開發環境的搭建(Goland & VS Code)

02. 學習五種變量建立的方法

03. 詳解資料類型:**整形與浮點型**

04. 詳解資料類型:byte、rune與string

05. 詳解資料類型:數組與切片

06. 詳解資料類型:字典與布爾類型

07. 詳解資料類型:指針

08. 面向對象程式設計:結構體與繼承

09. 一篇文章了解 Go 裡的函數

10. Go語言流程控制:if-else 條件語句

11. Go語言流程控制:switch-case 選擇語句

12. Go語言流程控制:for 循環語句

13. Go語言流程控制:goto 無條件跳轉

14. Go語言流程控制:defer 延遲調用

15. 面向對象程式設計:接口與多态

16. 關鍵字:make 和 new 的差別?

17. 一篇文章了解 Go 裡的語句塊與作用域

18. 學習 Go 協程:goroutine

19. 學習 Go 協程:詳解信道/通道

20. 幾個信道死鎖經典錯誤案例詳解

21. 學習 Go 協程:WaitGroup

22. 學習 Go 協程:互斥鎖和讀寫鎖

23. Go 裡的異常處理:panic 和 recover

24. 超詳細解讀 Go Modules 前世今生及入門使用

25. Go 語言中關于包導入必學的 8 個知識點

26. 如何開源自己寫的子產品給别人用?

27. 說說 Go 語言中的類型斷言?

28. 這五點帶你了解Go語言的select用法

14. Go 語言中的類型斷言是什麼?