zoukankan      html  css  js  c++  java
  • go语言 nil一些注意的地方

    nil

    nil 是go语言中预先定义的标识符,不是关键字或保留字。
    我们可以直接使用nil,而不用声明它。
    而且我们可以定义一个名称为 nil 的变量,比如下面这样:

    var nil = errors.New("my god")

    虽然上面的声明语句可以通过编译,但是并不提倡这么做。

    默认值nil

    在go语言中,布尔类型的零值(初始值)为 false数值类型的零值为 0字符串类型的零值为空字符串""
    除此之外其它类型的默认值为nil,nil可以代表下面这些类型的零值:

    • 指针类型(包括unsafe中的)
    • map类型
    • slice类型
    • function类型
    • channel类型
    • interface类型


    nil没有默认类型

    预先定义的nil是唯一的一个go语言中没有默认类型的非类型值。对于编译器来说,必须从上下文中获取充足的信息才能推断出nil的类型。
    当你把nil赋值给一个channel类型变量,此时为channel类型。
    当你把nil赋值给map类型变量,此时为map类型。


    不同类型的nil值占用的内存大小可能是不一样的

    一个类型的所有的值的内存布局都是一样的。nil也不例外。nil的大小一致与同类型中的非nil类型的值的大小一样大。但是不同类型的nil值的大小可能不同.

    package main
    
    import (
    "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
    }
    

      

    不同类型 nil 的指针是一样的

    package main
    import (
    "fmt"
    )
    func main() {
    var arr []int
    var num *int
    fmt.Printf("%p
    ", arr)
    fmt.Printf("%p", num)
    }

    运行结果如下所示:
    PS D:code> go run .main.go
    0x0
    0x0

    通过运行结果可以看出 arr 和 num 的指针都是 0x0。


    不同类型的 nil 是不能比较的

    两个相同类型的 nil 值也可能无法比较

    在Go语言中 map、slice 和 function 类型的 nil 值不能比较,比较两个无法比较类型的值是非法的,下面的语句无法编译。

    package main
    import (
    "fmt"
    )
    func main() {
    var s1 []int
    var s2 []int
    fmt.Printf(s1 == s2)
    }

    运行结果如下所示:
    PS D:code> go run .main.go
    # command-line-arguments
    .main.go:10:19: invalid operation: s1 == s2 (slice can only be compared to nil)
    但可以将不可比较类型的空值直接与 nil 标识符进行比较,如下所示:

    package main
    import (
    "fmt"
    )
    func main() {
    var s1 []int
    fmt.Println(s1 == nil)
    }

    运行结果如下所示:
    PS D:code> go run .main.go
    true

    对nil channel,map,slice和array 指针进行range操作也是合法的。

    • 对nil map和slice的循环次数将是0
    • 对nil数组的循环次数将取决于它的数组类型定义的长度
    • 对nil channel的range操作将永远阻塞当前goroutine

    例如,下面的代码将打印0,1,2,3和4,然后永远阻塞。hello, world和bye将永远不会被打印

    for range []int(nil) {
    fmt.Println("Hello")
    }
    
    for range map[string]string(nil) {
    fmt.Println("world")
    }
    
    for i := range (*[5]int)(nil) {
    fmt.Println(i)
    }
    
    for range chan bool(nil) { // block here
    fmt.Println("Bye")
    }
    
     
    

      


    如果类型T的零值是用预先定义的nil来表示的话,*new(T)产生一个nil T类型的值

    package main
    
    import "fmt"
    
    func main() {
    fmt.Println(*new(*int) == nil) // true
    fmt.Println(*new([]int) == nil) // true
    fmt.Println(*new(map[int]bool) == nil) // true
    fmt.Println(*new(chan string) == nil) // true
    fmt.Println(*new(func()) == nil) // true
    fmt.Println(*new(interface{}) == nil) // true
    }

    new()返回是一个指向新分配内存的地址,*可以对地址取值。

  • 相关阅读:
    mailServer Apache James / sendmail / qmail
    transactionServer IBM CICS / BEA Tuxedo
    java security / SSL / TLS / md5 / sha / base64 / rsa / des / aes / 3des / Blowfish
    growing
    framework osworkflow / jbpm
    8086CPU的16位寄存器
    寄存器AX
    寄存器AX
    8086CPU的16位寄存器
    8086CPU的8位寄存器数据存储情况
  • 原文地址:https://www.cnblogs.com/-wenli/p/12576686.html
Copyright © 2011-2022 走看看