不得不知道的golang知識點之nil

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

golang中的nil,很多人都誤以為與Java、PHP等程式設計語言中的null一樣。但是實際上Golang的niu複雜得多了,如果不信,那我們繼續往下閱讀。

nil 為預聲明的標示符,定義在builtin/builtin.go

// nil is a predeclared identifier representing the zero value for a// pointer, channel, func, interface, map, or slice type.// Type must be a pointer, channel, func, interface, map, or slice typevar nil Type // Type is here for the purposes of documentation only. It is a stand-in// for any Go type, but represents the same type for any given function// invocation.type Type int

nil的零值

按照Go語言規範,任何類型在未初始化時都對應一個零值:布爾類型是false,整型是0,字串是"",而指標、函數、interface、slice、channel和map的零值都是nil。

PS:這裡沒有說結構體struct的零值為nil,因為struct的零值與其屬性有關

nil沒有預設的類型,儘管它是多個類型的零值,必須顯式或隱式指定每個nil用法的明確類型。

package mainfunc main() {    // 明確.    _ = (*struct{})(nil)    _ = []int(nil)    _ = map[int]bool(nil)    _ = chan string(nil)    _ = (func())(nil)    _ = interface{}(nil)    // 隱式.    var _ *struct{} = nil    var _ []int = nil    var _ map[int]bool = nil    var _ chan string = nil    var _ func() = nil    var _ interface{} = nil}

如果關注過golang關鍵字的同學就會發現,裡面並沒有nil,也就是說nil並不是關鍵字,那麼就可以在代碼中定義nil,那麼nil就會被隱藏。

package mainimport "fmt"func main() {    nil := 123    fmt.Println(nil) // 123    var _ map[string]int = nil //cannot use nil (type int) as type map[string]int in assignment}

nil類型的地址和值大小

nil類型的所有值的記憶體布局始終相同,換一句話說就是:不同類型nil的記憶體位址是一樣的。

package mainimport (    "fmt")func main() {    var m map[int]string    var ptr *int    var sl []int    fmt.Printf("%p\n", m)       //0x0    fmt.Printf("%p\n", ptr )    //0x0    fmt.Printf("%p\n", sl )     //0x0}

業務中一般將nil值表示為異常。nil值的大小始終與其類型與nil值相同的non-nil值大小相同。因此, 表示不同零值的nil標識符可能具有不同的大小。

package mainimport (    "fmt"    "unsafe")func main() {    var p *struct{} = nil    fmt.Println( unsafe.Sizeof( p ) ) // 8    var s []int = nil    fmt.Println( unsafe.Sizeof( s ) ) // 24    var m map[int]bool = nil    fmt.Println( unsafe.Sizeof( m ) ) // 8    var c chan string = nil    fmt.Println( unsafe.Sizeof( c ) ) // 8    var f func() = nil    fmt.Println( unsafe.Sizeof( f ) ) // 8    var i interface{} = nil    fmt.Println( unsafe.Sizeof( i ) ) // 16}

大小是編譯器和體繫結構所依賴的。以上列印結果為64位體繫結構和正式 Go 編譯器。對於32位體繫結構, 列印的大小將是一半。

對於正式 Go 編譯器, 同一種類的不同類型的兩個nil值的大小始終相同。例如, 兩個不同的切片類型 ( []int和[]string) 的兩個nil值始終相同。

nil值比較

1.不同類型的nil是不能比較的。

package mainimport (    "fmt")func main() {    var m map[int]string    var ptr *int    fmt.Printf(m == ptr) //invalid operation: m == ptr (mismatched types map[int]string and *int)}

在 Go 中, 兩個不同可比較類型的兩個值只能在一個值可以隱式轉換為另一種類型的情況下進行比較。具體來說, 有兩個案例兩個不同的值可以比較:

  • 兩個值之一的類型是另一個的基礎類型。
  • 兩個值之一的類型實現了另一個值的類型 (必須是介面類型)。

nil值比較並沒有脫離上述規則。

package mainimport (    "fmt")func main() {    type IntPtr *int    fmt.Println(IntPtr(nil) == (*int)(nil))            //true    fmt.Println((interface{})(nil) == (*int)(nil))    //false}

2.同一類型的兩個nil值可能無法比較
因為golang中存在map、slice和函數類型是不可比較類型,它們有一個別稱為不可比擬的類型,所以比較它們的nil亦是非法的。

package mainimport (    "fmt")func main() {    var v1 []int = nil    var v2 []int = nil    fmt.Println(v1 == v2)    fmt.Println((map[string]int)(nil) == (map[string]int)(nil))    fmt.Println((func())(nil) == (func())(nil))}

不可比擬的類型的值缺是可以與“純nil”進行比較。

package mainimport (    "fmt")func main() {    fmt.Println((map[string]int)(nil) == nil)  //true    fmt.Println((func())(nil) == nil)           //true}

3.兩nil值可能不相等

如果兩個比較的nil值之一是一個介面值, 而另一個不是, 假設它們是可比較的, 則比較結果總是 false。原因是在進行比較之前, 介面值將轉換為介面值的類型。轉換後的介面值具有具體的動態類型, 但其他介面值沒有。這就是為什麼比較結果總是錯誤的。

package mainimport (    "fmt")func main() {    fmt.Println( (interface{})(nil) == (*int)(nil) ) // false}

常見問題

1.函數返回

func nilReturn() (string,error)  {    return nil,nil  //cannot use nil as type string in return argument}

因為error是介面類型所以error類型沒有報錯。

2.map的nil key
map的key為指標、函數、interface、slice、channel和map,則key可以為nil。

package mainimport (    "fmt")func main() {    mmap := make(map[*string]int,4)    a:="a"    mmap[&a] = 1    mmap[nil] = 99    fmt.Println(mmap)   //map[0xc042008220:1 <nil>:99]}

總結

nil之所以比較難以理解因為我們經常混淆了nil值和nil類型,希望各位同學細細品味其中區別。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.