我们知道,Go语言数组的定长性和值拷贝限制了其使用场景,Go提供另一种数据类型slice,可以看着一种变长数组,其数据结构中有指向数组的指针,所以是一种引用类型。在开发中关于切片和数组怎么选择?
先看看数组有什么问题?
Go 数组是值类型,赋值和函数传参 *** 作都会复制整个数组数据,下面代码是验证Go都是值复制:
func main() {
aa := [3]int{9,9,6}
var bb [3]int
bb = aa
fmt.Printf("aa=%p,%d\nbb=%p,%d",&aa,aa,&bb,bb)
}
输出结果:
aa=0xc0000b4000,[9 9 6]
bb=0xc0000b4018,[9 9 6]
两个地址都不一样,这样可以证明它们赋值和函数传参都是值复制。
那么问题就暴露出来,假想每次传参都用数组,每次数组都要被复制一遍。数组大小有 100万,在64位机器上就需要花费大约 800W 字节,即 8MB 内存。这样会消耗掉大量的内存。那么,就要解决这个问题?Go语言开发者,想到了使用函数传参用数组的指针。
func main() {
aa := []int{9,9,6}
test(&aa) //传数组指针
bb := aa[:] //切片
test(&bb)
fmt.Printf("aa=%p %v\n",&aa,&bb)
}
func test(num *[]int) {
fmt.Printf("func Array : %p , %v\n", num, *num)
(*num)[1] += 100
}
输出结果:
func Array : 0xc00011c018 , [9 9 6]
func Array : 0xc00011c048 , [9 109 6]
aa=0xc00011c018 &[9 209 6]
指针确实到达了我们想要的效果了,但是指针有个问题,打印结果可以看到,第一行和第三行指针地址都是同一个,万一原数组的指针指向更改了,那么函数里面的指针指向都会跟着更改。
切片的优势也就表现出来了。用切片传数组参数,既可以达到节约内存的目的,也可以达到合理处理好共享内存的问题。打印结果第二行就是切片,切片的指针和原来数组的指针是不同的。
由此我们可以得出结论:把第一个大数组传递给函数会消耗很多内存,采用切片的方式传参可以避免上述问题。切片是引用传递,所以它们不需要使用额外的内存并且比使用数组更有效率。
但是,并非所有时候都适合用切片代替数组,因为切片底层数组可能会在堆上分配内存,而且小数组在栈上拷贝的消耗也未必比make 消耗大。
如何创建切片?
(1)由数组创建
语法结构:arr[i:n],其中,arr是数组,i表示开始索引,默认为0,n表示结束索引,默认len(arr)。
Arr[i:n]表示创建一个包含i-n个元素的切片,第一个元素是arr[i],最后一个元素是arr[n-1],如
var arr = [...]int{1,2,3,4,5,6}
s := arr[0:4]
(2)通过内置函数 make 创建切片
注:由 make 创建的切片各元素被默认初始化为切片元素类型 的零值 。 例如:
a := make([]int,10,15)
创建一个长度为,len=10,cap=15
(3)切片基本 *** 作
Len()Cap()Append()Copy() a := make([]int,1,3) //创建一个切片为int类型,len=1,cap=3
a = append(a,1)
a = append(a,1) //已经满啦
fmt.Printf("len = %d,cap = %d,slice = %v\n", len(a), cap(a),a)
a = append(a,1) //cap会自动扩容,以原来的2倍扩容
fmt.Printf("len = %d,cap = %d,slice = %v\n", len(a), cap(a),a)
输出:
len = 3,cap = 3,slice = [0 1 1]
len = 4,cap = 6,slice = [0 1 1 1]
Slice原理
切片的结构体由3部分构成,Pointer 是指向一个数组的指针,len 代表当前切片的长度,cap 是当前切片的容量。cap 总是大于等于 len 的。
ptr 指向Slice开头的元素len 是指说明Slice长度多少,方括号取值只能去到len里面的值cap 是代表整个arr从ptr开始到结束长度注:Slice是可以向后扩展,但不能向前扩展。取值不可以超过底层数组cap长度
Slice如何扩容首先,当添加元素超过capacity的长度的时,系统会重新分配更大的底层数组,旧的数组如有还有用就还在,不用Go语言垃圾回收机制自动清除,Slice触发扩容,是以原来数组*2(2倍)进行扩容。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)