【问题标题】:The zero value of a slice is not nil切片的零值不为零
【发布时间】:2015-08-28 16:35:56
【问题描述】:

我正在按照示例https://tour.golang.org/moretypes/10 我修改了期望得到相同结果的代码。我没有。这是一个错误,还是一个文档错误?旅游状态

nil 切片的长度和容量为 0。

我的 y 变量的长度和容量为 0。

package main

import "fmt"

func myPrint(z []int) {
    fmt.Println(z, len(z), cap(z))
    if z == nil {
        fmt.Println("nil!")
    }
}

func main() {
    var z  []int 
    y := []int {}
    myPrint(z)
    myPrint(y)
}

这是我的输出。

[] 0 0
nil!
[] 0 0

我期待第二个“零”~为什么我没有得到它?

【问题讨论】:

    标签: go slice


    【解决方案1】:

    您的y 变量不是切片的零值。它是通过空切片文字分配的。

    // both of these allocate a slice
    y := []int{}
    z := []int{1, 2, 3}
    

    【讨论】:

    • 那么游记上的文档不完全正确。
    【解决方案2】:

    您引用的文档指出 nil 切片的长度和容量为 0, 但不是 每个 长度和容量为零的切片都是 nil 切片。 The specification 只表示 未初始化 切片的值为 nil。

    这便于在未初始化 (nil) 的切片上支持 lencap。否则我们需要先检查非零以避免恐慌。 (这也适用于其他内置类型,如地图或通道。)

    fmt.Print 输出而言,行为上的差异类似于打印未初始化(nil)指针与指向空结构的指针:

    var s *struct{} // uninitialised pointer
    fmt.Println(s)  // <nil>
    
    s = &struct{}{} // pointer to an empty structure
    fmt.Println(s)  // &{}
    

    【讨论】:

    • 我不认为这是一个正确的答案,nil slice 不是指针,我喜欢@tgogos 的答案,nil 表示 slice 下的数组不是 init
    • @petelin 你是对的,切片不是指针。我已经删除了暗示它的声明。
    【解决方案3】:

    在这种情况下:

    var z []int 
    

    你已经声明了一个变量z,但是你没有初始化它。

    在这种情况下:

    y := []int {}
    

    你声明它并初始化它,你将它设置为一个空切片。将第二个表达式写得很长,这两个表达式之间的区别会更清楚:

    var y []int = []int {}
    

    【讨论】:

      【解决方案4】:

      nil VS empty 切片

      如果我们想到这样的切片:

      [pointer] [length] [capacity]
      

      然后:

      nil slice:   [nil][0][0]
      empty slice: [addr][0][0] // it points to an address
      

      来自:《行动起来》一书:

      零切片

      当您想要表示不存在的切片时,它们很有用,例如在返回切片的函数中发生异常时。

      // Create a nil slice of integers.
      var slice []int
      

      空切片

      当您想要表示一个空集合时,例如当数据库查询返回零结果时,空切片很有用。

      // Use make to create an empty slice of integers.
      slice := make([]int, 0)
      
      // Use a slice literal to create an empty slice of integers.
      slice := []int{}
      

      ? 无论您使用的是 nil 切片还是空切片,内置函数 appendlencap 的工作原理都是一样的。


      Go playground example:

      package main
      
      import (
          "fmt"
      )
      
      func main() {
      
          var nil_slice []int
          var empty_slice = []int{}
      
          fmt.Println(nil_slice == nil, len(nil_slice), cap(nil_slice))
          fmt.Println(empty_slice == nil, len(empty_slice), cap(empty_slice))
      
      }
      

      打印:

      true 0 0
      false 0 0
      

      【讨论】:

      • 我喜欢你的回答作为查看它的一种方式,但我认为确认(或否认)这是 nil 的实际内存布局会很有用片。 stackoverflow.com/a/39993797 好像说是。
      【解决方案5】:

      nil 切片的长度和容量为 0,并且没有底层数组。

      var s []string => 没有底层数组 var s = []string => 创建一个底层数组,但他的长度为 0。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-05
        • 2023-02-25
        • 1970-01-01
        • 2019-04-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多