從概念上來講,乙個介面型別的值(簡稱介面值)其實有兩個部分:乙個具體型別和該型別的乙個值。二者稱為介面的動態型別和動態值。比如下面宣告乙個介面變數 w 並賦值,那麼 w 介面值可以用如下圖表示:
介面的零值
介面的零值就是把它的動態型別和動態值都設為 nil,如下圖所示:
var w io.writer
// 介面的零值
在這種情況下就是乙個 nil 介面值,可以用 w == nil 或者 w != nil 來檢測乙個介面值是否時 nil。呼叫乙個 nil 介面的任何方法都會導致崩潰:
w.write(byte("hello"))
// panic:對空指標引用值
介面值的比較
介面值可以用 == 和 != 來做比較。如果兩個介面值都是 nil 或者二者的動態型別完全一致且二者動態值相等(使用動態型別的==操作符來比較),那麼兩個介面值相等。因為介面值是可以比較的,所以它們可以作為 map 的鍵,也可以作為 switch 語句的運算元。
注意:在比較兩個介面值時,如果兩個介面值的動態型別一致,但對應的動態值是不可以比較的(比如 slice),那麼這個比較會導致** panic:
package main
import
("fmt"
)func
main()
=int
fmt.
println
(x == x)
}
panic 資訊:
panic: runtime error: comparing uncomparable type int
goroutine 1 [running]:
main.main()
/users/qianghaohao/go/src/examplecode/main.go:9 +0x82
獲取介面值的動態型別
使用 fmt 包的 %t 可以列印某個介面值的動態型別,有助於問題除錯:
func
main()
輸出:
*os.file
nil 介面值和動態值為 nil 介面值的區別
nil 介面值:介面值的動態型別和動態值都為 nil。
動態值為 nil 的介面:介面值的動態型別有具體型別,動態值為 nil。
示例**分析:
const debug =
false
func
main()
f(buf)
}func
f(out io.writer)
}
當 debug 為 true 時,buf 為執行 bytes.buffer 物件的乙個指標,當呼叫函式 f 時,將 buf 賦給 out,此時 out 的動態值不是 nil,而是指向 byte.buffer 物件的指標。out 的動態型別是 *byte.buffer。隨後呼叫 out.write 函式,**正常執行,不會引發 panic。
當 debug 為 false 時,呼叫函式 f 時,將 buf 賦值給 out,此時 out 的動態值雖然時 nil,但其動態型別不是 nil,所以 out != nil 表示式為 true,隨後呼叫 out.write 函式,但是 write 函式的接收者為 nil,所以在底層拷貝 buffer 時會導致 panic(空指標引用),具體可以看看 write 函式的底層實現就知道了。
《Go語言程式設計》讀書筆記
go語言榮譽 執行時,沒有任何外部依賴 執行速度快,很適合開發共享軟體。加上,我之前一直用c 語言開發,go有更好的 c語言美稱。自動垃圾 原生併發程式設計 速度媲美c 程式。基於channel goroutine,適應多核系統開發 函式多重返回值 簡化錯誤處理 c語言風格。比如語言緊湊 格式化要求...
《go程式語言》讀書筆記
短變數宣告 是用來宣告和初始化區域性變數的 短變數宣告最少宣告乙個新變數,否則,無法通過編譯 指標別名允許我們不用變數的名字來方文變數 不僅僅指標產生別名,當複製其他引用型別 像slice,map,channel,甚至包括這裡引用型別的結構體 陣列和介面 的值的時候,也會產生別名 new函式是乙個內...
《c程式語言》讀書筆記
舉例如下 char a 10 1 定義的時候直接用字串賦值 char a 10 hello 注意 不能先定義再給它賦值,如 char a 10 a 10 hello 這樣是錯誤的!2 對陣列中字元逐個賦值 char a 10 3 利用strcpy char a 10 strcpy a,hello 易...