Go 语言中的 nil 切片 vs 非 nil 切片 vs 空切片 [英] nil slices vs non-nil slices vs empty slices in Go language

查看:29
本文介绍了Go 语言中的 nil 切片 vs 非 nil 切片 vs 空切片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Go 编程的新手.我在 Go 编程书中读到切片由三件事组成:指向数组的指针、长度和容量.

I am a newbee to Go programming. I have read in go programming book that slice consists of three things: a pointer to an array, length and capacity.

我在 nil 切片(切片没有可指向的底层数组,len = 0,cap=0)、只有 len = 0,cap = 0 的非 nil 切片和空切片之间感到困惑.

I am getting confused between nil slices(slice has no underlying array to point to, len = 0,cap=0), non-nil slices where only len = 0,cap = 0 and empty slices.

谁能告诉我 nil 和 empty slice 是不是一回事?如果两者都不同,那么请说说这两者的区别是什么?

Can anyone please tell whether nil and empty slices are same things? If they both are different, then please tell what is the difference between those two?

如何判断一个切片是否为空?

How to test whether a slice is empty or not?

另外,指针在长度和容量为零的非 nil 切片中持有什么值?

Also, what value does the pointer holds in non-nil slices, whose length and capacity are zero?

推荐答案

可观察行为

nil 和空切片(容量为 0)不一样,但它们的可观察行为是一样的.我的意思是:

Observable behavior

nil and empty slices (with 0 capacity) are not the same, but their observable behavior is the same. By this I mean:

  • 您可以将它们传递给内置的 len()cap() 函数
  • 您可以范围超过它们(将是 0 次迭代)
  • 您可以对它们进行切片(通过不违反 规范:切片表达式 中概述的限制);因此结果也将是一个空切片)
  • 因为它们的长度是 0,所以你不能改变它们的内容(附加一个值会创建一个新的切片值)
  • You can pass them to the builtin len() and cap() functions
  • You can for range over them (will be 0 iterations)
  • You can slice them (by not violating the restrictions outlined at Spec: Slice expressions; so the result will also be an empty slice)
  • Since their length is 0, you can't change their content (appending a value creates a new slice value)

看这个简单的例子(一个 nil 切片和 2 个非 nil 空切片):

See this simple example (a nil slice and 2 non-nil empty slices):

var s1 []int         // nil slice
s2 := []int{}        // non-nil, empty slice
s3 := make([]int, 0) // non-nil, empty slice

fmt.Println("s1", len(s1), cap(s1), s1 == nil, s1[:], s1[:] == nil)
fmt.Println("s2", len(s2), cap(s2), s2 == nil, s2[:], s2[:] == nil)
fmt.Println("s3", len(s3), cap(s3), s3 == nil, s3[:], s3[:] == nil)

for range s1 {}
for range s2 {}
for range s3 {}

输出(在 Go Playground 上试试):

Output (try it on the Go Playground):

s1 0 0 true [] true
s2 0 0 false [] false
s3 0 0 false [] false

(请注意,切片 nil 切片会导致 nil 切片,切片非 nil 切片会导致非 nil 切片.)

(Note that slicing a nil slice results in a nil slice, slicing a non-nil slice results in a non-nil slice.)

您只能通过将切片值与预先声明的标识符 nil 进行比较来区分它们,它们在其他方面的表现都相同.

You can only tell the difference by comparing the slice value to the predeclared identifier nil, they behave the same in every other aspect.

要判断切片是否为空,只需将其长度与 0 进行比较:len(s) == 0.它是nil 切片还是非nil 切片都没有关系,它是否具有正容量也没有关系;如果没有元素,则为空.

To tell if a slice is empty, simply compare its length to 0: len(s) == 0. It doesn't matter if it's the nil slice or a non-nil slice, it also doesn't matter if it has a positive capacity; if it has no elements, it's empty.

s := make([]int, 0, 100)
fmt.Println("Empty:", len(s) == 0, ", but capacity:", cap(s))

打印(在 Go Playground 上试试):

Prints (try it on the Go Playground):

Empty: true , but capacity: 100

引擎盖下

切片值由reflect.SliceHeader:

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

nil 切片的情况下,这个结构体将有它的零值,即它的所有字段都将是它们的零值,即:0.

In case of a nil slice, this struct will have its zero value which is all its fields will be their zero value, that is: 0.

有一个非nil切片,容量和长度都等于0LenCap字段肯定会是 0,但 Data 指针可能不是.它不会,这就是它与 nil 切片的区别.它将指向一个零大小的底层数组.

Having a non-nil slice with both capacity and length equal to 0, Len and Cap fields will most certainly be 0, but the Data pointer may not be. It will not be, that is what differentiates it from the nil slice. It will point to a zero-sized underlying array.

请注意,Go 规范允许大小为 0 的不同类型的值具有相同的内存地址.规范:系统注意事项:大小和对齐保证:

Note that the Go spec allows for values of different types having 0 size to have the same memory address. Spec: System considerations: Size and alignment guarantees:

如果结构或数组类型不包含大小大于零的字段(或元素),则其大小为零.两个不同的零大小变量可能在内存中具有相同的地址.

A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.

让我们检查一下.为此,我们调用 unsafe 包的帮助,并获得"我们切片值的 reflect.SliceHeader 结构视图":

Let's check this. For this we call the help of the unsafe package, and "obtain" the reflect.SliceHeader struct "view" of our slice values:

var s1 []int
s2 := []int{}
s3 := make([]int, 0)

fmt.Printf("s1 (addr: %p): %+8v
",
    &s1, *(*reflect.SliceHeader)(unsafe.Pointer(&s1)))
fmt.Printf("s2 (addr: %p): %+8v
",
    &s2, *(*reflect.SliceHeader)(unsafe.Pointer(&s2)))
fmt.Printf("s3 (addr: %p): %+8v
",
    &s3, *(*reflect.SliceHeader)(unsafe.Pointer(&s3)))

输出(在 Go Playground 上试试):

Output (try it on the Go Playground):

s1 (addr: 0x1040a130): {Data:       0 Len:       0 Cap:       0}
s2 (addr: 0x1040a140): {Data: 1535812 Len:       0 Cap:       0}
s3 (addr: 0x1040a150): {Data: 1535812 Len:       0 Cap:       0}

我们看到了什么?

  • 所有切片(切片头)具有不同的内存地址
  • nil 切片有 0 数据指针
  • s2s3 切片确实具有相同的数据指针,共享/指向相同的 0 大小的内存值
  • All slices (slice headers) have different memory addresses
  • The nil slice has 0 data pointer
  • s2 and s3 slices do have the same data pointer, sharing / pointing to the same 0-sized memory value

这篇关于Go 语言中的 nil 切片 vs 非 nil 切片 vs 空切片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆