這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
GO比較容易混淆的地方
GO在nil判斷等方面容易混淆。
nil
GO的nil是帶類型的,可以參考相關的文章。看下面的代碼:
import ( "io" "fmt")type MyWriter struct {}func (w *MyWriter) Write(p []byte) (n int, err error) { return}func main() { var m *MyWriter fmt.Println("ptr m==nil?", bool(m==nil)) var o io.Writer = m fmt.Println("interface o==nil?", bool(o==nil)) if a,ok := o.(*MyWriter); true { fmt.Println("dynamic covert ok?", ok, "and a==nil?", bool(a==nil)) } o = func()io.Writer{ var m *MyWriter return m }() fmt.Println("return o==nil?", bool(o==nil)) func(o io.Writer) { fmt.Println("params o==nil?", bool(o==nil)) }(m) os.Exit(0)}
結果比較奇特:
ptr m==nil? trueinterface o==nil? falsedynamic covert ok? true and a==nil? truereturn o==nil? falseparams o==nil? false
簡單的規則就是一條,nil是有類型的:
var m *MyWriter = nil// 實際上是帶類型的(type, value):var m *MyWriter = ((*MyWriter)nil, nil)
因此,在比較的時候,都是帶類型比較:
var m *MyWriter = nilif m == nil {// 相當於:if m == ((*MyWriter)nil, nil) {// 這個地方當然是相等的,類型等,值也等。
但是換成其他的類型就不等了:
var m *MyWriter = nilvar o io.Writer = m//這時候的o實際上是:((*MyWriter)nil,nil)if o == ((io.Writer)nil, nil) {
這個在傳回值和參數時就非常重要,特別是參數:
func(o io.Writer) { fmt.Println("params o==nil?", bool(o==nil)) }(m)
大部分的時候,傳遞過來的肯定不是介面,而是某個指標,除非直接調用,否則都是非nil的,只有下面這種直接調用情況是nil:
func(o io.Writer) { fmt.Println("params o==nil?", bool(o==nil)) }(nil)
這個確實比較容易混淆。