Go   发布时间:2022-04-09  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了golang 数据二 (切片)大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

在项目开发过程中,更多的场景是需一个长度可以动态更新的数据存储结构,切片本身并非是动态数组或数组指针,他内部通过指针引用底层数组,并设定相关属性将@R_@L_874_2@_1861@操作限定在指定区域内。比如:

/runtime/slice.go

typeslicestruct{
	arrayunsafe.Pointer
	lenint
	capint
}

@H_944_5@切片初始化

切片有两种基本初始化方式:

//make([]T,len,cap)//T是切片的数据的类型,len表示length,cap表示capacity
{
s:=make([]int,5)//len:5cap:5
s:=make([]int,5,10)//len:5cap:10
s:=[]int{1,2,3}
}

{
arr:=[...]int{0,1,3,4,6,7,8,9}
s1:=arr[:]
s2:=arr[2:5]
s3:=arr[2:5:7]
s4:=arr[4:]
s5:=arr[:4]
s6:=arr[:4:6]

fmt.Println("s1:",s1,len(s1),cap(s1))
fmt.Println("s2:",s2,len(s2),cap(s2))
fmt.Println("s3:",s3,len(s3),cap(s3))
fmt.Println("s4:",s4,len(s4),cap(s4))
fmt.Println("s5:",s5,len(s5),cap(s5))
fmt.Println("s6:",s6,len(s6),cap(s6))
}
输出:
s1:[0123456789]1010
s2:[234]38
s3:[234]35
s4:[456789]66
s5:[0123]410
s6:[0123]46

通过上例说明cap 是表示切片所引用数组片段的真实长度,len是表示已经赋过值的最大下标(索引)值加1.

注意下面两种初始化方式的区别:

{
vara[]int
b:=[]int{}
fmt.Println(a==nil,b==nil)

fmt.Printf("a:%#v\n",(*reflect.SliceHeader)(unsafe.Pointer(&a)))
fmt.Printf("b:%#v\n",(*reflect.SliceHeader)(unsafe.Pointer(&b)))
fmt.Printf("asize%d\n",unsafe.Sizeof(a))
fmt.Printf("bsize%d\n",unsafe.Sizeof(b))
}
输出:
truefalse
a:&reflect.SliceHeader{Data:0x0,Len:0,Cap:0}
b:&reflect.SliceHeader{Data:0x5168b0,Cap:0}
asize24
bsize24
说明:
1.变量b的内部指针被赋值,即使该指针指向了runtime.zerobase,但它依然完成了初始化操作
2.变量a表示一个未初始化的切片对象,切片本身依然会分配所需的内存

切片之间不支持逻辑运算符,仅能判断是否为nil,比如:

{
vara[]int
b:=[]int{}
fmt.Println(a==b)//invalidoperation:a==b(slicecanonlybecomparedtonil)
}

@H_944_5@reslice

在原slice的基础上进行新建slice,新建的slice依旧指向原底层数组,新创建的slice不能超出原slice

的容量,但是不受其长度限制,并且如果修改新建slice的值,对所有关联的切片都有影响,比如:

{
s:=[]String{"a","b","c","d","e","f","g"}

s1:=s[1:3]//b,c
fmt.Println(s1,cap(s1))
s1_1:=s1[2:5]//c,d,e
fmt.Println(s1_1,len(s1_1),cap(s1_1))
}
输出:
[bc]26
[def]34

@H_944_5@append

向切片尾部追加数据,返回新的切片对象; 数据被追加到原底层数组,如果超出cap限制,则为新切片对象重新分配数组,新分配的数组cap是原数组cap的2倍,比如:

{
s:=make([]int,5)
s=append(s,1)
s=append(s,5)
fmt.Printf("%p,%v,%d\n",s,cap(s))

s=append(s,6)//重新分配内存
fmt.Printf("%p,cap(s))
}
输出:
0xc420010210,[12345],5
0xc4200140a0,[123456],10

如果是向nil切片追加数据,则会高频率的重新分配内存和数据复制,比如:

{
vars[]int
fmt.Printf("%p,cap(s))
fori:=0;i<10;i++{
s=append(s,i)
fmt.Printf("%p,cap(s))
}
}

所以为了避免程序运行中的频繁的资源开销,在某些场景下建议预留出足够多的空间。

@H_944_5@copy

两个slice之间复制数据时,允许指向同一个底层数组,并允许目标区间重叠。最终复制的长度以较短的切片长度(len)为准,比如:

{
s1:=[]int{0,6}
s2:=[]int{7,9}
copy(s1,s2)
fmt.Println(s1,cap(s1))
s1=[]int{0,6}
s2=[]int{7,9}
copy(s2,s1)
fmt.Println(s2,cap(s2))
}

那么可不可以在同一切片之间复制数据呢?

在项目开发过程中,如果slice长时间引用一个大数组中很小的片段,那么建议新建一个独立的切片,并复制出所需的数据,以便原数组内存可以被gc及时释优化回收。

大佬总结

以上是大佬教程为你收集整理的golang 数据二 (切片)全部内容,希望文章能够帮你解决golang 数据二 (切片)所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。