網站首頁 編程語言 正文
空接口
定義
空接口是特殊形式的接口類型,普通的接口都有方法,而空接口沒有定義任何方法口,也因此,我們可以說所有類型都至少實現了空接口。
type test interface { }
每一個接口都包含兩個屬性,一個是值,一個是類型。
var i interface{} fmt.Printf("類型:%T----值:%v\n", i, i) //類型:<nil>----值:<nil>
可見對于空接口來說,這兩者都是 nil
使用場景
第一,通常我們會直接使用 interface{}
作為類型聲明一個實例,而這個實例可以承載任意類型的值。
func main() { var i interface{} i = 100 fmt.Println(i) //100 i = "yif" fmt.Println(i) //yif i = 3.14 fmt.Println(i) //3.14 i = false fmt.Println(i) //false }
第二,如果想讓你的函數可以接收任意類型的值 ,也可以使用空接口。如下代碼都正常打印:
func main() { i := 100 s := "yif" f := 3.14 test(i) test(s) test(f) } func test(i interface{}) { fmt.Println(i) }
上面寫法有點麻煩,可以使用可變參數的函數。如下:
func main() { i := 100 s := "yif" f := 3.14 test(i, s, f) } func test(res ...interface{}) { fmt.Println(res) //res是切片 for k, v := range res { fmt.Println(k, v) } }
結果:
D:\workspace\go\src\test>go run main.go
[100 yif 3.14]
0 100
1 yif
2 3.14?
第三,你也定義一個可以接收任意類型的 array、slice、map、strcut,例如這邊定義一個切片
func main() { sli := make([]interface{}, 4) sli[0] = 100 sli[1] = "yif" sli[2] = []int{1, 2, 3} sli[3] = [...]int{5, 6, 7} fmt.Println(sli) for k, v := range sli { fmt.Println(k, v) } }
結果:
D:\workspace\go\src\test>go run main.go
[100 yif [1 2 3] [5 6 7]]
0 100
1 yif
2 [1 2 3]
3 [5 6 7]?
空接口幾個要注意的坑
**第一,**空接口可以承載任意值,但不代表任意類型就可以承接空接口類型的值
空接口類型可以保存任何值,也可以從空接口中取出原值。
但要是你把一個空接口類型的對象,再賦值給一個固定類型(比如 int, string等類型)的對象賦值,是會報錯的。
var i interface{} = 100 var t int = i // cannot use i (type interface {}) as type int in assignment: need type assertion
但是你使用短變量聲明,是可以的:
var i interface{} = 100 t := i fmt.Println(t) //100
因為編譯器會根據等號右邊的值來推導變量的類型完成初始化。
**第二:**當空接口承載數組和切片后,該對象無法再進行切片
sli := []int{1, 2, 3, 4} var i interface{} i = sli fmt.Println(i[1:2]) //cannot slice i (type interface {})
類型斷言
類型斷言(Type Assertion)是一個使用在接口值上的操作,用于檢查接口類型變量所持有的值是否實現了期望的接口或者具體的類型
類型斷言,僅能對靜態類型為空接口(interface{})的對象進行斷言,否則會拋出錯誤
Go語言中類型斷言的兩種語法
在Go語言中類型斷言的第一種語法格式如下:
t := i.(T)
這個表達式可以斷言一個接口對象(i)里不是 nil,并且接口對象(i)存儲的值的類型是 T,如果斷言成功,就會返回值給 t,如果斷言失敗,就會觸發 panic。
func main() { var i interface{} = 100 t := i.(int) fmt.Println(t) //100 fmt.Println("------------------------------------") s := i.(string) fmt.Println(s) }
結果【執行第二次斷言的時候失敗了,并且觸發了 panic】:
D:\workspace\go\src\test>go run main.go
100
------------------------------------
panic: interface conversion: interface {} is int, not stringgoroutine 1 [running]:
main.main()
? ? ? ? D:/workspace/go/src/test/main.go:32 +0x10e
exit status 2?
如果要斷言的接口值是 nil,那我們來看看也是不是也如預期一樣會觸發panic
var i interface{} var _ = i.(interface{})
結果:
D:\workspace\go\src\test>go run main.go
panic: interface conversion: interface is nil, not interface {}goroutine 1 [running]:
main.main()
? ? ? ? D:/workspace/go/src/test/main.go:27 +0x34
exit status 2?
在Go語言中類型斷言的另一種語法格式如下:
t, ok:= i.(T)
和上面一樣,這個表達式也是可以斷言一個接口對象(i)里不是 nil,并且接口對象(i)存儲的值的類型是 T,如果斷言成功,就會返回其類型給 t,并且此時 ok 的值 為 true,表示斷言成功。
如果接口值的類型,并不是我們所斷言的 T,就會斷言失敗,但和第一種表達式不同的事,這個不會觸發 panic,而是將 ok 的值設為 false ,表示斷言失敗,此時t 為 T 的零值。
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】:
D:\workspace\go\src\test>go run main.go
10-true
=====分隔線1=====
-false
=====分隔線2=====
<nil> - false
=====分隔線3=====
10-true
10-true?
上面這段輸出,你要注意的是第二個斷言的輸出在-false
之前并不是有沒有輸出任何 t2 的值,而是由于斷言失敗,所以 t2 得到的是 string 的零值也是 ""
,它是零長度的,所以你看不到其輸出。
類型斷言配合 switch 使用
如果需要區分多種類型,可以使用 type switch 斷言。
func main() { test(100) test("yif") test(3.14) var i interface{} //nil test(i) test(nil) } func test(i interface{}) { switch r := i.(type) { case int: fmt.Println(r, "是int型") case string: fmt.Println(r, "是字符串") case nil: fmt.Println(r, "是nil") default: fmt.Println("沒有結果!") } }
結果:
D:\workspace\go\src\test>go run main.go
100 是int型
yif 是字符串
沒有結果!
<nil> 是nil
<nil> 是nil
原文鏈接:https://juejin.cn/post/7078550092419956749
相關推薦
- 2022-06-19 C語言圖文并茂講解分支語句用法_C 語言
- 2022-05-16 C++實現圖書管理系統源碼_C 語言
- 2022-06-06 Element UI詳解el-scrollbar 滾動條組件 —— 監聽滾動條的滾動,跟隨頁面一起滾
- 2022-12-08 c++只保留float型的小數點后兩位問題_C 語言
- 2024-01-15 IDEA 常量字符串過長問題
- 2023-03-19 匯編語言LDR指令和LDR偽指令詳解_匯編語言
- 2022-07-07 Python常用內置函數和關鍵字使用詳解_python
- 2022-04-25 C#使用游標實現補間函數_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支