1. 程式人生 > 其它 >型別斷言

型別斷言

型別斷言是一個使用在介面值上的操作。語法上它看起來像x.(T)被成為斷言型別,這裡x表示一個介面的型別和T表示一個型別。一個型別斷言檢查它操作物件的動態型別是否和斷言的型別匹配。

這裡有兩種可能。
第一種,如果斷言的型別T是一個具體型別,然後型別斷言檢查x的動態型別是否和T相同。如果這個檢查成功了,型別斷言的結果是x的動態值,當然它的型別是T。換句話說,具體型別的型別斷言從它的操作物件中獲得具體的值。如果檢查失敗,接下來這個操作會丟擲panic。
var w io.Writer
w = os.Stdout
f := w.(*os.File)  // success: f == os.Stdout
c := w.(*bytes.Buffer) // panic

第二種,如果相反地斷言的型別T是一個介面型別,然後型別斷言檢查是否x的動態型別滿足T。如果這個檢查成功了,動態值沒有獲取到;這個介面仍然是一個有相同動態型別和值部分的介面之,但是結果為型別T。換句話說,對一個介面型別的型別斷言改吧了型別的表述方式,改變了可以獲取的方法集合(通常更大),但是它保留了介面值內部的動態型別和值的部分

在下面的第一個型別斷言後,w和rw都持有os.Stdout,因此他們都有一個動態型別*os.File,但是變數w是一個io.Writer型別,只對外公開了檔案的Write方法,而rw變數還公開了它的Read方法
var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter)  // success *os.File 
w = new(ByteCount)
rw = w.(io.ReadWriter) // panic  has no Read method

如果斷言操作的物件是一個nil介面值,那麼不論被斷言的型別是上面這個型別斷言都會失敗,我們幾乎不需要對一個更少限制性的介面型別(更少的方法集合)做斷言,因為它表現的就像是賦值操作一樣,除了對於nil介面值的情況。
w = rw
w = rw.(io.Writer) // fail


經常地,對一個介面值的動態型別我們是不確定的,並且我們更願意去檢驗它是否是一些特定的型別。如果型別斷言出現在一個預期有兩個結果的賦值操作中,例如如下的定義,這個操作不會再失敗的時候發生panic,但是替代地返回一個額外的第二個結果,這個結果是一個標識成功與否的布林值:
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

第二個結果通常賦值給一個命名為ok的變數,如果這個操作失敗了,那麼ok就是false值,第一個結果等於被斷言型別的零值,再這個例子中就是一個nil的*bytes.Buffer型別
這個ok結果經常立即用於決定程式下面做上面,if語句的拓展格式讓這個變的很簡潔:
if f, ok:= w.(*os.File); ok{
    //...
}

當型別斷言的操作物件是一個變數,你有時會看見原來的變數名重用而不是宣告一個新的本地變數名,這個重用的變數原來的值會被覆蓋(理解:其實是聲明瞭一個同名的新的本地變數,外層原來的w不會被改變),如下:
if w,ok := w.(*os.File);ok{
    //...
}

-------------------------------------------

個性簽名:程式碼過萬,鍵盤敲爛!!!

如果覺得這篇文章對你有小小的幫助的話,記得在右下角點個“推薦”哦,博主在此感謝!