Go 語(yǔ)言 類(lèi)型斷言

2023-03-14 16:55 更新

原文鏈接:https://gopl-zh.github.io/ch7/ch7-10.html


7.10. 類(lèi)型斷言

類(lèi)型斷言是一個(gè)使用在接口值上的操作。語(yǔ)法上它看起來(lái)像x.(T)被稱(chēng)為斷言類(lèi)型,這里x表示一個(gè)接口的類(lèi)型和T表示一個(gè)類(lèi)型。一個(gè)類(lèi)型斷言檢查它操作對(duì)象的動(dòng)態(tài)類(lèi)型是否和斷言的類(lèi)型匹配。

這里有兩種可能。第一種,如果斷言的類(lèi)型T是一個(gè)具體類(lèi)型,然后類(lèi)型斷言檢查x的動(dòng)態(tài)類(lèi)型是否和T相同。如果這個(gè)檢查成功了,類(lèi)型斷言的結(jié)果是x的動(dòng)態(tài)值,當(dāng)然它的類(lèi)型是T。換句話(huà)說(shuō),具體類(lèi)型的類(lèi)型斷言從它的操作對(duì)象中獲得具體的值。如果檢查失敗,接下來(lái)這個(gè)操作會(huì)拋出panic。例如:

var w io.Writer
w = os.Stdout
f := w.(*os.File)      // success: f == os.Stdout
c := w.(*bytes.Buffer) // panic: interface holds *os.File, not *bytes.Buffer

第二種,如果相反地?cái)嘌缘念?lèi)型T是一個(gè)接口類(lèi)型,然后類(lèi)型斷言檢查是否x的動(dòng)態(tài)類(lèi)型滿(mǎn)足T。如果這個(gè)檢查成功了,動(dòng)態(tài)值沒(méi)有獲取到;這個(gè)結(jié)果仍然是一個(gè)有相同動(dòng)態(tài)類(lèi)型和值部分的接口值,但是結(jié)果為類(lèi)型T。換句話(huà)說(shuō),對(duì)一個(gè)接口類(lèi)型的類(lèi)型斷言改變了類(lèi)型的表述方式,改變了可以獲取的方法集合(通常更大),但是它保留了接口值內(nèi)部的動(dòng)態(tài)類(lèi)型和值的部分。

在下面的第一個(gè)類(lèi)型斷言后,w和rw都持有os.Stdout,因此它們都有一個(gè)動(dòng)態(tài)類(lèi)型*os.File,但是變量w是一個(gè)io.Writer類(lèi)型,只對(duì)外公開(kāi)了文件的Write方法,而rw變量還公開(kāi)了它的Read方法。

var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter) // success: *os.File has both Read and Write
w = new(ByteCounter)
rw = w.(io.ReadWriter) // panic: *ByteCounter has no Read method

如果斷言操作的對(duì)象是一個(gè)nil接口值,那么不論被斷言的類(lèi)型是什么這個(gè)類(lèi)型斷言都會(huì)失敗。我們幾乎不需要對(duì)一個(gè)更少限制性的接口類(lèi)型(更少的方法集合)做斷言,因?yàn)樗憩F(xiàn)的就像是賦值操作一樣,除了對(duì)于nil接口值的情況。

w = rw             // io.ReadWriter is assignable to io.Writer
w = rw.(io.Writer) // fails only if rw == nil

經(jīng)常地,對(duì)一個(gè)接口值的動(dòng)態(tài)類(lèi)型我們是不確定的,并且我們更愿意去檢驗(yàn)它是否是一些特定的類(lèi)型。如果類(lèi)型斷言出現(xiàn)在一個(gè)預(yù)期有兩個(gè)結(jié)果的賦值操作中,例如如下的定義,這個(gè)操作不會(huì)在失敗的時(shí)候發(fā)生panic,但是替代地返回一個(gè)額外的第二個(gè)結(jié)果,這個(gè)結(jié)果是一個(gè)標(biāo)識(shí)成功與否的布爾值:

var w io.Writer = os.Stdout
f, ok := w.(*os.File)      // success:  ok, f == os.Stdout
b, ok := w.(*bytes.Buffer) // failure: !ok, b == nil

第二個(gè)結(jié)果通常賦值給一個(gè)命名為ok的變量。如果這個(gè)操作失敗了,那么ok就是false值,第一個(gè)結(jié)果等于被斷言類(lèi)型的零值,在這個(gè)例子中就是一個(gè)nil的*bytes.Buffer類(lèi)型。

這個(gè)ok結(jié)果經(jīng)常立即用于決定程序下面做什么。if語(yǔ)句的擴(kuò)展格式讓這個(gè)變的很簡(jiǎn)潔:

if f, ok := w.(*os.File); ok {
    // ...use f...
}

當(dāng)類(lèi)型斷言的操作對(duì)象是一個(gè)變量,你有時(shí)會(huì)看見(jiàn)原來(lái)的變量名重用而不是聲明一個(gè)新的本地變量名,這個(gè)重用的變量原來(lái)的值會(huì)被覆蓋(理解:其實(shí)是聲明了一個(gè)同名的新的本地變量,外層原來(lái)的w不會(huì)被改變),如下面這樣:

if w, ok := w.(*os.File); ok {
    // ...use w...
}


以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)