x.(T)
檢查x的動(dòng)態(tài)類型是否是T,其中x必須是接口值。
- 如果T是具體類型
類型斷言檢查x的動(dòng)態(tài)類型是否等于具體類型T。如果檢查成功,類型斷言返回的結(jié)果是x的動(dòng)態(tài)值,其類型是T。換句話說,對接口值x斷言其動(dòng)態(tài)類型是具體類型T,若成功則提取出x的具體值。如果檢查失敗則panic。
例如:
var w io.Writer
w = os.Stdout //os.Stdout是一個(gè)類型為*os.File的包級別變量
f := w.(*os.File) //斷言接口w的動(dòng)態(tài)類型是具體類型*os.File,斷言成功,返回os.Stdout給f
c := w.(*bytes.Buffer) //斷言接口w的動(dòng)態(tài)類型是具體類型*bytes.Buffer,斷言失敗,panic
- 如果T是接口類型
類型斷言檢查x的動(dòng)態(tài)類型是否滿足T。如果檢查成功,x的動(dòng)態(tài)值不會(huì)被提取,返回值是一個(gè)類型為T的接口值。換句話說,到接口類型的類型斷言,改變了表達(dá)式的類型,改變了(通常是擴(kuò)大了)可以訪問的方法,且保護(hù)了接口值內(nèi)部的動(dòng)態(tài)類型和值。
例如:
var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter) //成功:*os.File同時(shí)有Read和Write方法
w = new(ByteCounter) //有Write方法
rw = w.(io.ReadWriter) // panic: *ByteCounter沒有Read方法
- 無論T是什么類型,如果x是nil接口值,則類型斷言失敗。
- 類型斷言到一個(gè)較少限制(較少方法)的接口類型基本是不需要的,因?yàn)檫@個(gè)行為和賦值一樣(除了nil的情況):
w = rw // io.ReadWriter賦值給io.Writer
w = rw.(io.Writer) //和上面一樣,僅當(dāng)rw為nil時(shí)失敗,而上面如果rw為nil則w被賦值為nil
如果我們想知道類型斷言是否失敗,而不是失敗時(shí)觸發(fā)panic,可以使用返回兩個(gè)值的版本:
y, ok := x.(T)
當(dāng)檢查成功時(shí)ok為true。例如:
var w io.Writer = os.Stdout
f, ok := w.(*os.File) //成功:f為os.Stdout,ok為true
b, ok := w.(*bytes.Buffer) //失敗:b為零值,這里是nil, ok為false,no panic
ok值通常立刻用于決定是否執(zhí)行下一步,慣用法:
if f, ok := w.(*os.File); ok {
// ... use f ...
}
類型斷言用于查詢可能的行為,例子:
package main
import (
"io"
"os"
)
//這個(gè)例子展示了類型斷言用于選擇可能的行為,這兒如果一個(gè)io.Writer支持WriteString則可以直接使用,從而避免分配臨時(shí)內(nèi)存
func writeString(w io.Writer, s string) (n int, err error) {
type stringWriter interface {
WriteString(string) (n int, err error)
}
if sw, ok := w.(stringWriter); ok {
//fmt.Print("<use WriteString>")
return sw.WriteString(s) // avoid temporary copy
}
return w.Write([]byte(s)) // allocate temporary copy
}
func writeHeader(w io.Writer, contentType string) error {
if _, err := writeString(w, "Content-Type: "); err != nil {
return err
}
if _, err := io.WriteString(w, contentType); err != nil { //系統(tǒng)自帶的io.WriteString實(shí)現(xiàn)和上面一樣
return err
}
return nil
}
func main() {
writeHeader(os.Stdout, "test")
}
- 接口值可有包含各種不同的具體類型值,而類型斷言就是用于從接口中動(dòng)態(tài)的區(qū)分出各種具體的類型,從而可以使用具體的類型。
- Type Switches
switch x.(type){
case nil: // 如果x是nil
case int, uint:
case bool:
case string;
default: //沒有匹配上
}
//case的順序是有意義的,因?yàn)榭赡芡瑫r(shí)滿足多個(gè)接口,不可以用fallthrough, default的位置無所謂。
如果需要提取具體的值:
switch x := x.(type) { /* ... */ } //前面的x是一個(gè)局部變量,因?yàn)閟witch創(chuàng)建了一個(gè)詞法域
//x的類型就是每個(gè)case的類型,如果case有多個(gè)類型,則類型為interface{}