nil slice, non-nil slice, empty slice in Go language

WBOY
Release: 2024-02-08 21:18:08
forward
1177 people have browsed it

Go 语言中 nil 切片、非 nil 切片、空切片

php editor Xiaoxin brings you an introduction to the slice types in the Go language. In Go language, slices have three states: nil slice, non-nil slice and empty slice. These three slicing states have different meanings and characteristics when used. Understanding the differences between these slice types will help us better understand and use the slice function in the Go language. Next, let’s explore the specific features and uses of these three slice types.

Question content

I am new to Go programming. I read in a Go programming book that a slice consists of three parts: a pointer to the array, the length, and the capacity.

I'm confused about the following:

  • nil slice (the slice does not point to the underlying array, len = 0, cap=0)
  • Only non-zero slices with len = 0, cap = 0
  • Empty slice.

Can anyone tell me if nil and empty slice are the same thing? If both are different then please tell me what is the difference between these two? How to test if a slice is empty? Also, what value does a pointer hold in a non-zero slice with zero length and capacity?

Solution

Observable Behavior

nilis not the same as an empty slice (capacity 0), but their observable behavior is the same (almost always). I mean:

  • You can pass them to the built-inlen()andcap()functions
  • You canfor rangeoverride them (will be 0 iterations)
  • You can slice them (as long as it doesn't violate the restrictions outlined inSpecification: Slicing Expressions; so the result will also be an empty slice)
  • Since their length is 0, you cannot change their contents (appending a value creates a new slice value)

Check out this simple example (onenilslice and 2 non-nilempty 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 {}
Copy after login

Output (try it onGo Playground):

s1 0 0 true [] true s2 0 0 false [] false s3 0 0 false [] false
Copy after login

(Note that slicing anilslice produces anilslice, and slicing a non-nilslice produces a non-nilslice.)

With the exception that you can only tell the difference by comparing the slice value to the predeclared identifiernil, they all behave identically in other respects.But be aware that many packages do compare slices toniland may do things differently based on that (e.g.encoding/jsonandfmtpackages).

The only difference isconverting the slice to an array pointer(added to the language inGo 1.17). Converting a non-nilslice to an array pointer produces a non-nilpointer, and converting anilslice to an array pointer produces anilpointer.

To determine if a slice is empty, simply compare its length to0:len(s) == 0. Whether it's anilslice or a non-nilslice, it doesn't matter whether 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))
Copy after login

Print (try it onGo Playground):

Empty: true , but capacity: 100
Copy after login

bottom

Slice values are represented by structures defined inreflect.SliceHeader:

type SliceHeader struct { Data uintptr Len int Cap int }
Copy after login

For anilslice, the structure will have its zero value, i.e. all its fields will have zero values, i.e.:0.

If the capacity and length of the non-nilslice is equal to the0,LenandCapfields, it is most likely0, but theDatapointer may not be. Itwon't, that's what differentiates it from anilslice. It will point to a zero-sized underlying array.

Please note that the Go specification allows values of different types with size 0 to have the same memory address.Specifications: System Notes: Size and Alignment Guarantees:

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

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)))
Copy after login

输出(在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}
Copy after login

我们看到了什么?

  • 所有切片(切片头)都有不同的内存地址
  • nil切片具有0数据指针
  • s2s3切片确实具有相同的数据指针,共享/指向相同的 0 大小的内存值

The above is the detailed content of nil slice, non-nil slice, empty slice in Go language. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!