nil スライスと空のスライスの違いは何ですか? 次のコードを通じてそれについて学習します。
package main
import (
"fmt"
"reflect"
"unsafe"
)
func TestSlice() {
// nil 切片初始化方式
var s1 []int
// 空切片初始化方式
s2, s3 := make([]int, 0), make([]int, 0)
fmt.Printf("s1=%+v,s2=%+v,s3=%+v \n", s1, s2, s3)
fmt.Printf("s1=%p,s2=%p,s3=%p \n", &s1, &s2, &s3)
fmt.Printf("s1==nil?%v\n", s1 == nil)
fmt.Printf("s2==nil?%v\n", s2 == nil)
// 输出切片底层数据结构
fmt.Printf("s1 pointer:%+v, s2 pointer:%+v, s4 pointer:%+v, \n", *(*reflect.SliceHeader)(unsafe.Pointer(&s1)), *(*reflect.SliceHeader)(unsafe.Pointer(&s2)), *(*reflect.SliceHeader)(unsafe.Pointer(&s3)))
fmt.Printf("s1 pointer:%+v, s2 pointer:%+v, s4 pointer:%+v, \n", (*reflect.SliceHeader)(unsafe.Pointer(&s1)), (*reflect.SliceHeader)(unsafe.Pointer(&s2)), (*reflect.SliceHeader)(unsafe.Pointer(&s3)))
// 输出切片底层 data 的地址(引用数组指针地址)
fmt.Printf("&s1.data == &s2.data ?%v\n", (*(*reflect.SliceHeader)(unsafe.Pointer(&s1))).Data == (*(*reflect.SliceHeader)(unsafe.Pointer(&s2))).Data)
fmt.Printf("&s2.data == &s3.data ?%v\n", (*(*reflect.SliceHeader)(unsafe.Pointer(&s2))).Data == (*(*reflect.SliceHeader)(unsafe.Pointer(&s3))).Data)
}
func main() {
TestSlice()
}
出力:
s1=[],s2=[],s3=[]
s1=0xc000118000,s2=0xc000118018,s3=0xc000118030
s1==nil?true
s2==nil?false
s1 pointer:{
Data:0 Len:0 Cap:0}, s2 pointer:{
Data:18412560 Len:0 Cap:0}, s4 pointer:{
Data:18412560 Len:0 Cap:0},
s1 pointer:&{
Data:0 Len:0 Cap:0}, s2 pointer:&{
Data:18412560 Len:0 Cap:0}, s4 pointer:&{
Data:18412560 Len:0 Cap:0},
&s1.data == &s2.data ?false
&s2.data == &s3.data ?true
結論:
nil スライスと空のスライスは異なるアドレスを指します。nil の空スライス参照配列ポインタ アドレスは 0 (実際のアドレスを指しません)、空スライス参照配列ポインタ アドレスは存在し、値に固定されています。
// slice 底层数据结构
type SliceHeader struct {
Data uintptr //引用数组指针地址
Len int // 切片的目前使用长度
Cap int // 切片的容量
}
nil スライスと空のスライスの最大の違いは、それらが指す配列参照アドレスが異なることです。
例如:
s1 pointer:&{
Data:0 Len:0 Cap:0}, s2 pointer:&{
Data:18412560 Len:0 Cap:0}, s4 pointer:&{
Data:18412560 Len:0 Cap:0},