go slice详解

本文详细介绍了Go语言中的slice数据结构,包括其指向底层数组、长度与容量的概念,以及扩容机制。当cap小于1024时,扩容会翻倍;当cap大于等于1024时,扩容按1.25倍增长。append函数用于添加元素,若容量不足则分配新数组。copy函数用于切片拷贝,不会引起扩容。最后,文章强调了预分配内存以优化性能的重要性,并对比了slice与数组在不同容量下的性能差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

array指向底层数组,len表示切片长度,cap表示数组容量

slice的扩容机制

	newcap := old.cap
	doublecap := newcap + newcap
	if cap > doublecap {
		newcap = cap
	} else {
		if old.cap < 1024 {
			newcap = doublecap
		} else {
			// Check 0 < newcap to detect overflow
			// and prevent an infinite loop.
			for 0 < newcap && newcap < cap {
				newcap += newcap / 4
			}
			// Set newcap to the requested cap when
			// the newcap calculation overflowed.
			if newcap <= 0 {
				newcap = cap
			}
		}
	}

当cap < 1024:
每次扩容 *2
当cap >= 1024:
每次 * 1.25
append函数将元素追加到slice的末尾。如果有足够的容量,则将新元素追加进去。否则,将分配一个新的底层数组。append返回更新的切片。因此,有必要将append的结果存储在保存切片本身的变量中

slice copy

使用copy()内置函数拷贝两个切片时,会将源切片的数据逐个拷贝到目的切片指向的数组中,拷贝数量取两个切片长度的最小值。
例如长度为10的切片拷贝到长度为5的切片时,将会拷贝5个元素。
也就是说,copy过程中不会发生扩容。

例子

func test(s[] int)  {
	s[0] = 100
}

func main() {
	var s []int
	for i := 0; i < 10; i ++ {
		s = append(s, i)
	}
	test(s)
	fmt.Println(s)
}

输出结果:

[100 1 2 3 4 5 6 7 8 9]
func test(s[] int)  {
	s = append(s, 1000)
	s[0] = 100
	fmt.Println("test里面s长度: ", len(s))
	fmt.Println("test里面s容量: ", cap(s))
}

func main() {
	var s []int
	for i := 0; i < 10; i ++ {
		s = append(s, i)
	}
	fmt.Println("test前长度: ", len(s))
	fmt.Println("test前容量: ", cap(s))
	test(s)
	fmt.Println("test后长度: ", len(s))
	fmt.Println("test后容量: ", cap(s))
	fmt.Println(s)
}
test前长度:  10
test前容量:  16
test里面s长度:  11
test里面s容量:  16
test后长度:  10
test后容量:  16
[100 1 2 3 4 5 6 7 8 9]

注意:函数传递的是slice结构体的复制版本,它们的指针指向同一个底层数组地址,但是容量和长度的变化是各自不影响的,因此1000在外面没有打印出来

总结

1.预先分配内存避免切片扩容,可以提升性能。
2.扩容的时候如果原Slice容量小于1024,则新Slice容量将扩大为原来的2倍;如果原Slice容量大于等于1024,则新Slice容量将扩大为原来的1.25倍。
3.数组和 slice 在1000以内的容量上时性能一致,10000~1000000容量时数组的效率就比slice好了一倍,10000000容量往后数组性能大幅度下降,slice 是数组性能的两倍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值