切片的零值不是nil。

huangapple go评论78阅读模式
英文:

The zero value of a slice is not nil

问题

我正在为您翻译以下内容:

我按照https://tour.golang.org/moretypes/10的示例进行操作。我修改了代码,期望得到相同的结果。但实际上没有。这是一个错误还是文档错误?教程中提到:

> 一个空的切片的长度和容量都为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

我期望第二个"nil",为什么没有出现?

英文:

I was following the example https://tour.golang.org/moretypes/10
I modified the code expecting to get the same result. I did not. Is this a bug, or a documentation error? The tour states

> A nil slice has a length and capacity of 0.

My y variable has a length and capacity of 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)
}

Here is my output.

[] 0 0
nil!
[] 0 0

I was expecting a second "nil"~ Why didn't I get it?

答案1

得分: 34

nil切片

如果我们将切片表示为:

[指针] [长度] [容量]

那么:

nil切片:   [nil][0][0]
空切片: [地址][0][0] // 它指向一个地址

来自《Go in action》书籍:

nil切片

当你想表示一个不存在的切片时,它们非常有用,比如在返回切片的函数中发生异常时。

// 创建一个整数的nil切片。
var slice []int

空切片

当你想表示一个空集合时,空切片非常有用,比如当数据库查询返回零结果时。

// 使用make创建一个空的整数切片。
slice := make([]int, 0)
// 使用切片字面量创建一个空的整数切片。
slice := []int{}

👉 无论你使用nil切片还是空切片,内置函数appendlencap的工作方式都是相同的。


Go playground示例:

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 Vs empty slice

If we think of a slice like this:

[pointer] [length] [capacity]

then:

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

> From: "Go in action" book:
> ### nil slice
They’re useful when you want to represent a slice that doesn’t exist, such as when an exception occurs in a function that returns a slice.

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

> ### empty slice
Empty slices are useful when you want to represent an empty collection, such as when a database query returns zero results.

> // 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{}

> 👉 Regardless of whether you’re using a nil slice or an empty slice, the built-in functions append, len, and cap work the same.


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))

}

prints:

true 0 0
false 0 0

答案2

得分: 20

你引用的文档指出,一个空的切片的长度和容量都为0,但并不是说每个长度和容量为0的切片都是空切片。规范只是说一个未初始化的切片的值是nil。

这是为了方便支持对未初始化(nil)的切片使用lencap。否则,我们需要先检查非nil值,以避免发生panic。(这也适用于其他内置类型,如映射或通道。)

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

var s *struct{} // 未初始化的指针
fmt.Println(s)  // <nil>

s = &struct{}{} // 指向空结构体的指针
fmt.Println(s)  // &{}
英文:

The doc you referenced states that a nil slice has a length and capacity of 0, but not that every slice of length and capacity of zero is a nil slice. The specification only says that the value of an uninitialized slice is nil.

This is a convenience to support len and cap on slices which are uninitialised (nil). Otherwise we would need to check for non-nil first in order to avoid panic. (This also holds for other in-built types like maps or channels.)

In terms of the fmt.Print output, the difference in behaviour is similar to printing an uninitialised (nil) pointer vs pointer to an empty structure:

var s *struct{} // uninitialised pointer
fmt.Println(s)  // &lt;nil&gt;

s = &amp;struct{}{} // pointer to an empty structure
fmt.Println(s)  // &amp;{}

答案3

得分: 9

在这种情况下:

var z []int 

你声明了一个变量 z,但没有对其进行初始化。

在这种情况下:

y := []int {}

你声明并初始化了它,将其设置为空切片。以更长的方式编写第二个表达式可以更清楚地区分这两个表达式:

var y []int = []int {}
英文:

In this case:

var z []int 

You have declared a variable z but you did not initialize it.

In this case:

y := []int {}

You declared it and initialized it, you set it to an empty slice. Writing the second expression the long way makes the difference between the two expressions more clear:

var y []int = []int {}

答案4

得分: 6

你的 y 变量并不是切片的零值。它是通过一个空切片字面量进行分配的。

// 这两个都分配了一个切片
y := []int{}
z := []int{1, 2, 3}
英文:

Your y variable isn't the zero value for a slice. It's allocated via an empty slice literal.

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

答案5

得分: 0

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

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

英文:

> A nil slice has a length and capacity of 0 and has no underlying array.

var s []string => no underlying array
var s = []string => create a underlying array but his length is 0.

huangapple
  • 本文由 发表于 2015年6月12日 23:33:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/30806931.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定