很多物件導向的語言都有介面這個概念。go 語言的介面的獨特之處在於它是隱式實現。換句話說,對於乙個具體的型別,無序宣告它實現了哪些介面,只要提供介面所必需的方法即可。
乙個介面型別定義了一套方法,如果乙個具體型別要實現該介面,那麼必須實現介面型別定義的所有方法。
如果乙個型別實現了乙個介面所要求的所有方法,那麼這個型別就實現了這個介面。
從概念上來講,乙個介面型別的值(簡稱介面值)其實有兩個部分:乙個具體型別和該型別的乙個值。二者稱為介面的動態型別和動態值。var w io.writer
w = os.stdout // ok: *os.file 有 write 方法
w =new(bytes.buffer)
// ok: *bytes.buffer 有 write 方法
w = time.second // 編譯錯誤: time.duration 缺少 write 方法
var rwc io.readwritecloser
rwc = os.stdout // ok: *os.file 有 read、write、close 方法
rwc =
new(bytes.buffer)
// 編譯錯誤: *bytes.buffer 缺少 close 方法
// 當右側表示式也是乙個介面時,該規則也有效:
w = rwc
rwc = w // 編譯錯誤:io.writer 缺少 close 方法
介面值可以用 == 和 != 操作符來做比較。如果兩個介面值都是 nil 或者二者的動態型別完全一致且二者動態值相等(使用動態型別的 == 操作符來做比較),那麼兩個介面值相等。因為介面值是可以比較的,所以它們可以作為 map 的鍵,也可以作為 switch 語句的運算元。
需要注意的是,在比較兩個介面值時,如果兩個介面值的動態型別一致,但對應的動態值是不可比較的(比如 slice),那麼這個比較會以崩潰的方式失敗:
型別斷言是乙個作用在介面值上的操作,寫出來類似於 x.(t),其中 x 是乙個介面型別的表示式,而 t 是乙個型別(稱為斷言型別)。型別斷言會檢查作為運算元的動態型別是否滿足指定的斷言型別。var x inte***ce=[
]int
fmt.
println
(x == x)
// 宕機:試圖比較不可比較的型別 int
這兒有兩個可能。首先,如果斷言型別t是乙個具體型別,那麼型別斷言會檢查 x 的動態型別是否就是 t。如果檢查成功,型別斷言的結果就是 x 的動態值,型別當然就是t。換句話說,型別斷言就是用來從它的運算元中把具體的型別提取出來的操作。
其次,如果斷言型別t 是乙個介面型別,那麼型別斷言檢查 x 的動態型別是否滿足 t。如果檢查成功,動態值並沒有提取出來,結果仍然是乙個介面值。var w io.writer
w = os.stdout
f := w.
(*os.file)
// 成功: f == os.stdout
c := w.
(*bytes.buffer)
// 崩潰:介面持有的是 *os.file, 不是 *bytes.buffer
考慮一下os 包中的檔案操作返回的錯誤集合, i/o 會因為很多原因失敗,但有三類原因通常必須單獨處理:檔案已儲存(建立操作),檔案沒找到(讀取操作)以及許可權不足。os 包提供了三個幫助函式用來對錯誤進行分類:
但由於處理 i/o 錯誤的邏輯會隨著平台的變化而變化,因此這種方式很不健壯,同樣的錯誤可能會用完全不同的錯誤訊息來報告。package os
func
i***ist
(err error
)bool
func
isnotexist
(err error
)bool
func
ispermission
(err error
)bool
func
isnotexist
(err error
)bool
乙個更可靠的方法是用專門的型別來表示結構化的錯誤值。os 包定義了乙個 patherror 型別來表示在與乙個檔案路徑相關的操作上發生錯誤(比如 open 或者 delete),乙個類似的 linkerror 用來表述在於兩個檔案路徑相關的操作上發生的錯誤(比如 symlink 和 rename).
型別分支的最簡單形式與普通分支語句類似,兩個的差別是運算元改為 x.(type)var errnotexist = errors.
new(
"file dose not exist"
)// isnotexist 返回乙個布林值,該值表明錯誤是否代表檔案或目錄不存在
func
isnotexist
(err error
)bool
return err == syscall.enoent || err == errnotexist
}
與普通的 switch 語句類似,分支是按順序來判定的,當乙個分支符合時,對應的**會執行。分支的順序在乙個或多個介面型別時變得很重要,因為有可能兩個分支都能滿足。default 分支的位置無關緊要。另外,型別分支不允許使用 fallthrough。var x inte***ce
switch x.
(type
)
Go 介面,介面繼承
demo.go 介面繼承 package main import fmt 父介面 type humen inte ce 子介面 type person inte ce 學生類 type student struct 學生類的方法 讓學生類符合父介面的規則 func stu student sayhe...
Go語言的介面
介面是一種抽象型別,是對其他型別行為的概括與抽象,從語法角度來看,介面是一組方法定義的集合。很多物件導向的語言都有介面這個概念,但go語言介面的獨特之處在於它是隱式實現。換句話說,對於乙個具體的型別,無須宣告它實現了哪些介面,只要提供介面所必需的方法即可。這種設計讓程式設計人員無須改變已有型別的實現...
Go的介面總結
一 什麼是介面 二 什麼是介面值 乙個介面值可以持有任意大的動態值,不論動態值多大,介面值總是可以容下它 介面值的可比較性 注意 乙個包含nil指標的介面不是nil介面 空介面 此時呼叫介面方法會發生panic錯誤。即乙個介面值的動態型別type nil,但動態值value nil,此時的介面值 w...