在Go语言中,零片vs非零片与空片 [英] nil slices vs non-nil slices vs empty slices in Go language
问题描述
我是Go编程的新手。我已经读过编程书籍,该片由三件事组成:一个指向数组的指针,长度和容量。
我在零片之间感到困惑(片没有底层数组指向,len = 0,cap = 0),其中只有len = 0,cap = 0和空切片的非零切片
任何人都可以请告诉零和空片是否是相同的东西?
如果两者不同,那么请告诉我们这两者之间有什么区别?
如何测试切片是否为空?
另外,指针在非零切片中的长度和容量为零是什么值?
可观察行为
nil
和空片(0容量)不是相同,但他们可观察到的行为是相同的。我的意思是:
- 你可以将它们传递给内建的
len()
和
- 您可以<范围
范围
/ code>在它们之上(将会是0次迭代)
- 您可以切片(不违反;所以结果也是一个空片段)
- 由于它们的长度为0,所以可以不会改变它们的内容(附加一个值会创建一个新的切片值)
请看这个简单的例子(a
nil
切片和2个非 -nil
空切片):
var s1 [] int // nil slice
s2:= [] int {} //非零,空片
s3:= make([] int,0)/ /非零,空片
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 [:] ==无)
为_ =范围s1 {}
为_ =范围s2 {}
为_ =范围s3 {}
输出(尝试在 Go Playground ):
s1 0 0 true [] true
s2 0 0 false [] false
s3 0 0 false [] false
(请注意, code> nil slice会产生一个
nil
切片,将非 -> nil
slice会产生一个非 -nil
切片。)
您只能通过比较切片值到预先标识的标识符
nil
,它们在所有其他方面表现相同。
要判断一个片是否为空,只需比较它的长度为
0
:len(s)== 0
。无论它是nil
切片还是一个非 -nil
切片都没关系,也不要紧它具有积极的能力;
s:= make([] int,0,100)
如果它没有元素,它就是空的。 fmt.Println(Empty:,len(s)== 0,但容量:,cap(s))
打印(在去游乐场上试用):
空:true,但容量:100
引擎盖下
切片值由
reflect.SliceHeader
:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
在
nil
切片的情况下,该结构将具有其零值,这是它的所有字段将是它们的零值,即:0
。
有一个非
nil
切片的容量和长度等于0
,Len
和Cap
字段肯定会是0
,但数据
指针可能不是。它 will 不是,这是将它与nil
切片区分开来的原因。它会指向一个零大小的底层数组。
请注意,Go规范允许具有0大小的不同类型的值具有相同的内存地址。 规格:系统考量:尺寸和对齐保证:
如果结构或数组类型的大小不超过零,则它们的大小为零。 两个不同的零大小变量可能在内存中具有相同的地址。
让我们来检查一下。为此,我们呼叫
不安全
的帮助。包,并获取我们切片值的reflect.SliceHeader
structview:
var s1 [] int
s2:= [] int {}
s3:= make([] int,0)
fmt.Printf( s1(addr:%p):%+ 8v \ n,
& s1,*(* reflect.SliceHeader)(unsafe.Pointer(& s1)))
fmt.Printf (s2(addr:%p):%+ 8v \ n,
& s2,*(* reflect.SliceHeader)(unsafe.Pointer(& s2)))
fmt。 printf(s3(addr:%p):%+ 8v \ n,
& s3,*(* reflect.SliceHeader)(unsafe.Pointer(& s3)))
输出(在 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
数据指针 -
s2
和s3
切片具有相同的数据指针,共享/指向相同的0大小的内存值
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.
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.
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?
Also, what value does the pointer holds in non-nil slices, whose length and capacity are zero?
解决方案Observable behavior
nil
and empty slices (with 0 capacity) are not the same, but their observable behavior is the same. By this I mean:- You can pass them to the builtin
len()
andcap()
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)
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 {}
Output (try it on the Go Playground):
s1 0 0 true [] true s2 0 0 false [] false s3 0 0 false [] false
(Note that slicing a
nil
slice results in anil
slice, slicing a non-nil
slice results in a non-nil
slice.)You can only tell the difference by comparing the slice value to the predeclared identifier
nil
, they behave the same in every other aspect.To tell if a slice is empty, simply compare its length to
0
:len(s) == 0
. It doesn't matter if it's thenil
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))
Prints (try it on the Go Playground):
Empty: true , but capacity: 100
Under the hood
A slice value is represented by a struct defined in
reflect.SliceHeader
:type SliceHeader struct { Data uintptr Len int Cap int }
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
.Having a non-
nil
slice with both capacity and length equal to0
,Len
andCap
fields will most certainly be0
, but theData
pointer may not be. It will not be, that is what differentiates it from thenil
slice. It will point to a zero-sized underlying array.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.
Let's check this. For this we call the help of the
unsafe
package, and "obtain" thereflect.SliceHeader
struct "view" of our slice values:var s1 []int s2 := []int{} s3 := make([]int, 0) fmt.Printf("s1 (addr: %p): %+8v\n", &s1, *(*reflect.SliceHeader)(unsafe.Pointer(&s1))) fmt.Printf("s2 (addr: %p): %+8v\n", &s2, *(*reflect.SliceHeader)(unsafe.Pointer(&s2))) fmt.Printf("s3 (addr: %p): %+8v\n", &s3, *(*reflect.SliceHeader)(unsafe.Pointer(&s3)))
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}
What do we see?
- All slices (slice headers) have different memory addresses
- The
nil
slice has0
data pointer s2
ands3
slices do have the same data pointer, sharing / pointing to the same 0-sized memory value
这篇关于在Go语言中,零片vs非零片与空片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- 您可以<范围