数组(Array)和切片(Slice)
数组(Array)和切片(Slice)是Go语言中用于存储和操作一组相同类型元素的数据结构, 它们具有一些重要的区别.
数组(Array):
- 数组是具有固定长度的数据结构, 在声明时需要指定数组的长度.
- 数组的长度在创建时确定, 并且无法改变.
- 数组的元素类型必须相同.
- 可以使用索引操作符[]来访问和修改数组中的元素.
- 数组是值类型, 当将一个数组赋值给另一个数组时, 会进行值的复制.
- 数组在内存中是连续存储的.
示例代码:
var arr [5]int // 声明一个包含5个int类型元素的数组 arr := [3]string{"a", "b"} // 声明并初始化一个包含3个字符串类型元素的数组
切片(Slice):
- 切片是对数组的一个动态窗口或视图, 它可以具有可变长度.
- 切片没有固定的长度, 在创建时不需要指定长度.
- 切片是引用类型, 它指向底层的数组.
- 可以使用切片操作符[:]来创建切片, 并使用索引操作符[]来访问和修改切片中的元素.
- 可以使用append函数向切片添加元素, 动态增加切片的长度.
- 切片可以通过切片表达式或者使用make函数创建.
- 切片的底层数组的容量可能会大于切片的长度.
注意, 底层数组是可以被多个 slice 同时指向的, 因此对一个 slice 的元素进行操作是有可能影响到其他 slice 的.// runtime/slice.go type slice struct { array unsafe.Pointer // 底层数组指针 len int // 长度 cap int // 容量 }
- 切片操作符[:]: 使用切片操作符创建一个新的切片时, 新的切片与原始切片共享底层数组. 这种情况下, 对其中一个切片的修改会影响到其他共享底层数组的切片.
- append 函数: 如果一个切片通过 append 函数扩展了长度, 并且底层数组的容量足够容纳新的元素, 那么新的切片和原始切片将继续共享同一个底层数组.
- 赋值操作: 切片的赋值操作会创建一个新的切片变量, 新的切片变量将引用相同的底层数组. 这个过程中并没有发生底层数组的拷贝, 仅仅是切片变量的拷贝.
切片扩容
newcap = newlen ( newlen > oldcap * 2 )
当新slice长度(newlen)大于原slice容量(oldcap)2倍的时候, 新slice(newcap)容量为新长度;newcap = oldcap * 2 ( oldcap < 256 )
当原slice容量(oldcap)小于256的时候, 新slice(newcap)容量为原来的2倍;newcap = oldcap + (oldcap + 3*256) / 4 ( oldcap >= 256 )
原slice容量(oldcap)超过256, 新slice容量newcap = oldcap+(oldcap+3*256)/4.- 新slice会进行内存对齐.