golang数组、切片(slice)详解

本文深入探讨了Golang中的数组和切片,详细解释了切片的定义、append操作如何影响容量和长度的变化。通过实例代码,展示了切片在不同扩容条件下的增长策略,包括小于1024长度时的2倍增长,以及不同比例增加元素时容量的变化。同时,文章还讨论了切片拷贝和添加元素的情况,揭示了拷贝操作对原始切片的影响,以及如何使用`copy`函数实现无副作用的元素复制。
摘要由CSDN通过智能技术生成

1.切片,数组的定义

(1)数组的定义
主要有一下几种,直接上代码:

	// 1.数组的定义
	// 注意因为长度也是数组类型的一部分,所以 var a [1]int ; var b [2]int 时,a和b 是两个不同的数组
	var a1 [2]int
	a1[0] = 0
	a1[1] = 1
	fmt.Printf("数组定义------\n")
	fmt.Printf("a1:%v\n",a1)
	
	var a2 = []int{0,1,2}
	fmt.Printf("a2:%v\n",a2)
	
	var a3 = [...]int{0,1}
	fmt.Printf("a3:%v\n",a3)
	
	//var <数组名称> [<数组长度>]<数组元素> = [...]<元素类型>{索引1:元素1,索引2:元素2,...}
	var a4 = [...]int{1:0,0:1}	
	fmt.Printf("a4:%v\n\n",a4)
	/*
	数组定义------
	a1:[0 1]
	a2:[0 1]
	a3:[0 1]
	a4:[1 0]
	*/

(2)切片的定义

   // 2.切片的定义
	var s1 []int
	fmt.Printf("切片定义------\n")
	fmt.Printf("s1:%v\n",s1)
	
	s2 := make([]int,2)		//使用make内建函数定义并默认初始化为0,长度为2,其容量也为2,不指定默认与长度相等
	fmt.Printf("s2:%v\n\n",s2)
	/*
	切片定义------
	s1:[]
	s2:[0 0]
	*/

(3)探讨切片append函数后其容量和长度是怎么变化的?貌似是2倍增长?

// 3.切片容量探讨
	var slice []string
	fmt.Printf("slice 长度:%v   容量:%v\n",len(slice),cap(slice))

	slice = append(slice, "a")
	fmt.Printf("slice 长度:%v   容量:%v\n",len(slice),cap(slice))

	slice = append(slice, "b")
	fmt.Printf("slice 长度:%v   容量:%v\n",len(slice),cap(slice))

	slice = append(slice, "c")
	fmt.Printf("slice 长度:%v   容量:%v\n",len(slice),cap(slice))

	slice = append(slice, "d")
	fmt.Printf("slice 长度:%v   容量:%v\n",len(slice),cap(slice))

	slice = append(slice, "e")
	fmt.Printf("slice 长度:%v   容量:%v\n",len(slice),cap(slice))

	slice = slice[0:1]
	fmt.Printf("slice 长度:%v   容量:%v\n",len(slice),cap(slice))
	/*
	slice 长度:0   容量:0
	slice 长度:1   容量:1
	slice 长度:2   容量:2
	slice 长度:3   容量:4
	slice 长度:4   容量:4
	slice 长度:5   容量:8
	slice 长度:1   容量:8
	*/

从目前来看貌似增加元素个数一旦超过其原有的容量,新增后容量为原来的2倍,接着往下看。
以上代码在github上请点击

2.切片扩容的探讨

切片扩容时分以下几种情况:
(1)切片原有长度小于1024,每次新增元素个数不超过原有长度的1倍,结论:cap是2倍增长

	s1 := make([]int, 0)
	fmt.Printf("The capacity of s1: %d\n", cap(s1))
	for i := 1; i <= 17; i++ {
		s1 = append(s1, i)
		fmt.Printf("s1(%d): len: %d, cap: %d\n", i, len(s1), cap(s1))
	}
	fmt.Println()
	/*
	The capacity of s1: 0
	s1(1): len: 1, cap: 1
	s1(2): len: 2, cap: 2
	s1(3): len: 3, cap: 4
	s1(4): len: 4, cap: 4
	s1(5): len: 5, cap: 8
	s1(6): len: 6, cap: 8
	s1(7): len: 7, cap: 8
	s1(8): len: 8, cap: 8
	s1(9): len: 9, cap: 16
	s1(10): len: 10, cap: 16
	s1(11): len: 11, cap: 16
	s1(12): len: 12, cap: 16
	s1(13): len: 13, cap: 16
	s1(14): len: 14, cap: 16
	s1(15): len: 15, cap: 16
	s1(16): len: 16, cap: 16
	s1(17): len: 17, cap: 32
	*/

(2)切片原有长度小于1024,一次增加个数大于原有长度的1倍。结论:增加后的容量比你预想的总长度稍大一点

	s2 := make([]int, 10)
	fmt.Printf("The capacity of s2: %d\n", cap(s2))

	r1 := append(s2, make([]int, 5)...)
	fmt.Printf("r1: len: %d, cap: %d\n", len(r1), cap(r1))

	r2 := append(s2, make([]int, 11)...)
	fmt.Printf("r2: len: %d, cap: %d\n", len(r2), cap(r2))

	r3 := append(s2, make([]int, 21)...)
	fmt.Printf("r3: len: %d, cap: %d\n\n", len(r3), cap(r3))
	/*
	The capacity of s2: 10
	r1: len: 15, cap: 20
	r2: len: 21, cap: 22
	r3: len: 31, cap: 32
	*/

(3)切片原有长度大于1024,但是增加元素个数不超过原有长度的0.25倍。结论:容量不是2倍而是0.25倍增长

// 1024 * 0.25 = 256
	s3 := make([]int, 1024)
	fmt.Printf("The capacity of s3: %d\n", cap(s3))

	r4 := append(s3, make([]int, 200)...)
	fmt.Printf("r4: len: %d, cap: %d\n", len(r4), cap(r4))

	r5 := append(s3, make([]int, 256)...)
	fmt.Printf("r5: len: %d, cap: %d\n", len(r5), cap(r5))

	// 1280 * 0.25 = 320
	r6 := append(s3, make([]int, 266)...)
	fmt.Printf("r6: len: %d, cap: %d\n\n", len(r6), cap(r6))
	/*
	The capacity of s3: 1024
	r4: len: 1224, cap: 1280
	r5: len: 1280, cap: 1280
	r6: len: 1290, cap: 1696
	*/

(4)切片原有长度大于1024,一次增加元素个数超过原有长度的0.25倍。结论:容量比你预想的0.25倍累乘稍大一些。

	s4 := make([]int, 1024)
	fmt.Printf("The capacity of s4: %d\n", cap(s4))

	r7 := append(s3, make([]int, 256)...)
	fmt.Printf("r7: len: %d, cap: %d\n", len(r7), cap(r7))

	r8 := append(s3, make([]int, 300)...)
	fmt.Printf("r8: len: %d, cap: %d\n", len(r8), cap(r8))
	/*
	The capacity of s4: 1024
	r7: len: 1280, cap: 1280
	r8: len: 1324, cap: 1696
	*/

示例代码保存在GitHub地址:点击

3.切片拷贝,添加的探讨

(1)先看一段代码

	//示例1
	fmt.Printf("示例1------\n")
	a1 := []int{1,2,3,4,5,6,7,8,9}
	fmt.Printf("a1: %v\n",a1)
	
	a2 := a1[0:9]
	fmt.Printf("a2: %v\n",a2)
	
	a2[0] = -1
	fmt.Printf("a1: %v\n",a1)
	fmt.Printf("a2: %v\n",a2)
	/*
	示例1------
	a1: [1 2 3 4 5 6 7 8 9]
	a2: [1 2 3 4 5 6 7 8 9]
	a1: [-1 2 3 4 5 6 7 8 9]
	a2: [-1 2 3 4 5 6 7 8 9]
	*/

以上示例a2通a1获得,改变a2的同时,a1也同时改变,说明a2和a1指向的是同一个数组,底层数组改变了,指向他的变量全部改变。如果截取的长度超过原来a1的长度时呢?比如: a2 := append(a1, 1,2,3) ?, 接着往下看
(2)同样还是先看示例2一段代码

	//示例2
	fmt.Printf("示例2------\n")
	a3 := append(a1, 1,2,3)
	fmt.Printf("a3: %v\n",a3)

	a3[1] = -2
	fmt.Printf("a1: %v\n",a1)
	fmt.Printf("a3: %v\n",a3)
	/*
	示例2------
	a3: [-1 2 3 4 5 6 7 8 9 1 2 3]
	a1: [-1 2 3 4 5 6 7 8 9]
	a3: [-1 -2 3 4 5 6 7 8 9 1 2 3]
	*/

分析:a3[1]位置修改为-2,打印后,a1数组的值不变,a3的值为我们预想的,为什么呢?因为 a3 := append(a1, 1,2,3) 后的长度大于a1的长度,此时新开辟了一个内存空间给a3,打印后,就是如上结果。那如果我要截取a1其中一部分元素同时修改某些元素而不修改原有a1 的长度呢?接着往下看示例3.
(3)使用 “func copy(dst, src []Type) int” 函数

	//示例3
	fmt.Printf("示例3------\n")
	a4 := make([]int,9)
	fmt.Printf("拷贝元素个数为:%v\n",copy(a4,a1))
	fmt.Printf("a4: %v\n",a4)

	a4[3] = -4
	fmt.Printf("a1: %v\n",a1)
	fmt.Printf("a4: %v\n",a4)
	/*
	示例3------
	拷贝元素个数为:9
	a4: [-1 2 3 4 5 6 7 8 9]
	a1: [-1 2 3 4 5 6 7 8 9]
	a4: [-1 2 3 -4 5 6 7 8 9]
	*/

分析:copy 函数返回值为你拷贝的个数,拷贝后, 修改 a4[3] 元素,a1数组的值是不受影响的。
以上示例GitHub地址:请点击

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值