Go語(yǔ)言斷言和類型查詢的實(shí)現(xiàn)
1、類型斷言
類型斷言(Type Assertion)是一個(gè)使用在接口值上的操作,用于檢查接口類型變量所持有的值是否實(shí)現(xiàn)了期望的接口或者具體的類型。
在Go語(yǔ)言中類型斷言的語(yǔ)法格式如下:
// i.(TypeNname) value, ok := x.(T)
其中,x 表示一個(gè)接口的類型,如果是具體類型變量,則編譯器會(huì)報(bào)non-interface type xxx on left,T 表示一個(gè)具體的類型(也可為接口類型)。
該斷言表達(dá)式會(huì)返回 x 的值(也就是 value)和一個(gè)布爾值(也就是 ok),可根據(jù)該布爾值判斷 x 是否為 T 類型:
如果 T 是具體某個(gè)類型,類型斷言會(huì)檢查 x 的動(dòng)態(tài)類型是否等于具體類型 T。如果檢查成功,類型斷言返回的結(jié)果是 x 的動(dòng)態(tài)值,其類型是 T。
如果 T 是接口類型,類型斷言會(huì)檢查 x 的動(dòng)態(tài)類型是否滿足 T。如果檢查成功,x 的動(dòng)態(tài)值不會(huì)被提取,返回值是一個(gè)類型為 T 的接口值。
無(wú)論 T 是什么類型,如果 x 是 nil 接口值,類型斷言都會(huì)失敗。
示例代碼如下:
package main
import (
"fmt"
)
func main() {
var x interface{}
x = 10
value, ok := x.(int)
// 10,true
fmt.Print(value, ",", ok)
}
運(yùn)行結(jié)果如下:
# 程序結(jié)果
10,true
需要注意如果不接收第二個(gè)參數(shù)也就是上面代碼中的 ok,斷言失敗時(shí)會(huì)直接造成一個(gè) panic,如果 x 為 nil 同樣也會(huì) panic。
示例代碼如下:
package main
import (
"fmt"
)
func main() {
var x interface{}
x = "Hello"
value := x.(int)
fmt.Println(value)
}
運(yùn)行結(jié)果如下:
# 輸出結(jié)果
panic: interface conversion: interface {} is string, not int
接口斷言通??梢允褂?comma,ok 語(yǔ)句來(lái)確定接口是否綁定某個(gè)實(shí)例類型,或者判斷接口綁定的實(shí)例類型是否實(shí)現(xiàn)另一個(gè)接口。
re,ok := body.(io.ReadCloser) if,ok := r.Body.(*maxBytesReader);
2、類型查詢
接口類型查詢的語(yǔ)法格式如下:
switch v := i.(type){
case typel:
XXXX
case type2:
XXXX
default:
XXXX
}
接口查詢有兩層語(yǔ)義,一是查詢一個(gè)接口變量底層綁定的底層變量的具體類型是什么,二是查詢接口變量綁定的底
層變量是否還實(shí)現(xiàn)了其他接口。
(1)、i 必須是接口類型
具體類型實(shí)例的類型是靜態(tài)的,在類型聲明后就不再變化,所以具體類型的變量不存在類型查詢,類型查詢一定是
對(duì)一個(gè)接口變量進(jìn)行操作。也就是說(shuō),上文中的i必須是接口變量,如果i是未初始化接口變量,則v的值是 nil。
package main
import (
"fmt"
"io"
)
func main() {
var i io.Reader
//此處i是為未初始化的接口變量,所以v為nil
switch v := i.(type) {
case nil:
//<nil>
fmt.Printf("%T\n", v)
default:
fmt.Printf("default")
}
}
(2)、case 字句后面可以跟非接口類型名,也可以跟接口類型名,匹配是按照 case 子句的順序進(jìn)行的。
如果 case 后面是一個(gè)接口類型名,且接口變量i綁定的實(shí)例類型實(shí)現(xiàn)了該接口類型的方法,則匹配成,v的類型是接口類型,v底層綁定的實(shí)例是i綁定具體類型實(shí)例的副本。
如果 case 后面是一個(gè)具體類型名,且接口變量i綁定的實(shí)例類型和該具體類型相同,則匹配成功,此時(shí)v 就是該具體類型變量,v的值是i綁定的實(shí)例值的副本。
如果 case 后面跟著多個(gè)類型,使用逗號(hào)分隔,接口變量i綁定的實(shí)例類型只要和其中一個(gè)類型匹配,則直接使用o賦值給v,相當(dāng)于 v:=o。這個(gè)語(yǔ)法有點(diǎn)奇怪,按理說(shuō)編譯器不應(yīng)該允許這種操作,語(yǔ)言實(shí)現(xiàn)者可能想讓type switch 語(yǔ)句和普通的 switch 語(yǔ)句保持一樣的語(yǔ)法規(guī)則,允許發(fā)生這種情況。
如果所有的case字句都不滿足,則執(zhí)行 default 語(yǔ)句,此時(shí)執(zhí)行的仍然是 v:=o,最終v的值是o。此時(shí)使用v沒(méi)有任何意義。
fallthrough 語(yǔ)句不能在 Type Switch 語(yǔ)句中使用。
package main
import (
"fmt"
"io"
"log"
"os"
)
func main() {
var i io.Reader
// 此處i是為未初始化的接口變量,所以v為nil
switch v := i.(type) {
case nil:
// <nil>
fmt.Printf("%T\n", v)
default:
fmt.Printf("default")
}
f, err := os.OpenFile("notes.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
log.Fatal(err)
}
defer f.Close()
i = f
switch v := i.(type) {
// i的綁定的實(shí)例是*osFile類型,實(shí)現(xiàn)了io.ReadWriter接口,所以下面case匹配成功
case io.ReadWriter:
// v是io.ReadWriter接口類型,所以可以調(diào)用Write方法
v.Write([]byte("io.ReadWriter\n"))
// Type Switch Result: io.ReadWriter
fmt.Println("Type Switch Result: io.ReadWriter")
// 由于上一個(gè)case已經(jīng)匹配,就算這個(gè)case也匹配,也不會(huì)走到這里
case *os.File:
v.Write([]byte("*os.File\n"))
fmt.Println("Type Switch Result: *os.File")
//這里可以調(diào)用具體類型方法
v.Sync()
default:
fmt.Println("Type Switch Result: unknown")
return
}
switch v := i.(type) {
// 匹配成功,v的類型就是具體類型*os.File
case *os.File:
v.Write([]byte("*os.File\n"))
// Type Switch Result: *os.File
fmt.Println("Type Switch Result: *os.File")
v.Sync()
//由于上一個(gè)case已經(jīng)匹配,就算這個(gè)case也匹配,也不會(huì)走到這里
case io.ReadWriter:
//v是io.ReadWriter接口類型,所以可以調(diào)用Write方法
v.Write([]byte("io.ReadWriter\n"))
fmt.Println("Type Switch Result: io.ReadWriter")
default:
fmt.Println("Type Switch Result: unknown")
return
}
switch v := i.(type) {
//多個(gè)類型,f滿足其中任何一個(gè)就算匹配
case *os.File, io.ReadWriter:
// 此時(shí)相當(dāng)于執(zhí)行力v := i ,v和i是等價(jià)的,使用v沒(méi)有意義。
if v == i {
// true
fmt.Println(true)
}
default:
return
}
}
# 程序輸出
<nil>
Type Switch Result: io.ReadWriter
Type Switch Result: *os.File
true
package main
import (
"fmt"
)
func main() {
var a int
a = 10
// the type of a is int
getType(a)
}
func getType(a interface{}) {
switch a.(type) {
case int:
fmt.Println("the type of a is int")
case string:
fmt.Println("the type of a is string")
case float64:
fmt.Println("the type of a is float")
default:
fmt.Println("unknown type")
}
}
# 程序輸出
the type of a is int
到此這篇關(guān)于Go語(yǔ)言斷言和類型查詢的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Go語(yǔ)言斷言和類型查詢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語(yǔ)言安裝和GoLand2021最全超詳細(xì)安裝教程
Go語(yǔ)言和GoLand的關(guān)系好比于java和idea、python和pycharm,因此我們需要先安裝好Go語(yǔ)言后才能安裝GoLand。它的安裝和java,python的安裝大同小異,好了,下面給大家?guī)?lái)了GoLand2021安裝教程,需要的朋友參考下吧2021-08-08
Go高級(jí)特性探究之優(yōu)先級(jí)隊(duì)列詳解
Heap?是一種數(shù)據(jù)結(jié)構(gòu),這種數(shù)據(jù)結(jié)構(gòu)常用于實(shí)現(xiàn)優(yōu)先隊(duì)列,這篇文章主要就是來(lái)和大家深入探討一下GO語(yǔ)言中的優(yōu)先級(jí)隊(duì)列,感興趣的可以了解一下2023-06-06
Go 語(yǔ)言中靜態(tài)類型和動(dòng)態(tài)類型的使用
本文主要介紹了Go語(yǔ)言中的靜態(tài)類型和動(dòng)態(tài)類型,靜態(tài)類型在編譯時(shí)確定,提供了類型安全,性能優(yōu)化和代碼清晰,而動(dòng)態(tài)類型在運(yùn)行時(shí)確定,提供了更高的靈活性,但可能引發(fā)運(yùn)行時(shí)錯(cuò)誤,下面就來(lái)介紹一下,感興趣的可以了解一下2024-10-10
Golang中HTTP路由設(shè)計(jì)的使用與實(shí)現(xiàn)
這篇文章主要介紹了Golang中HTTP路由設(shè)計(jì)的使用與實(shí)現(xiàn),為什么要設(shè)計(jì)路由規(guī)則,因?yàn)槁酚梢?guī)則是HTTP的請(qǐng)求按照一定的規(guī)則 ,匹配查找到對(duì)應(yīng)的控制器并傳遞執(zhí)行的邏輯,需要的朋友可以參考下2023-05-05
Go語(yǔ)言開發(fā)前后端不分離項(xiàng)目詳解
這篇文章主要為大家介紹了Go語(yǔ)言開發(fā)前后端不分離項(xiàng)目詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11

