区别
1.数组长度固定,切片长度可变
2.数组是深拷贝,切片是浅拷贝,切片是引用类型
扩容规则 不同版本不一样
https://www.jb51.net/article/280481.htm#_lab2_2_1
go1.18
1.如果期望容量大于当前容量的两倍就会使用期望容量;
2.如果当前切片的容量小于阈值(默认 256)就会将容量翻倍;
3.如果当前切片的容量大于等于阈值(默认 256),小切片的2倍生长,大切片生长1.25倍;
go
package main
import "fmt"
func main() {
arr1 := [3]int{1, 2, 3}
arr2 := arr1
fmt.Printf("%p\n", &arr1[0])
fmt.Printf("%p\n", &arr2[0])
arr2[0] = 10
fmt.Println(arr1)
fmt.Println(arr2)
sli1 := []int{1, 2}
sli2 := sli1
fmt.Printf("%p\n", &sli1[0])
fmt.Printf("%p\n", &sli2[0])
sli2[0] = 10
fmt.Println(sli1)
fmt.Println(sli2)
sliceAppend(sli1)
fmt.Println(sli1)
}
// 不会改变原有slice长度
func sliceAppend(s []int) {
s = append(s, []int{2, 2, 2}...)
fmt.Printf("sliceAppend %d %d\n", len(s), len(s))
}
go
package main
import "fmt"
func main() {
sli1 := []int{1}
fmt.Printf("len=%d cap=%d\n", len(sli1), cap(sli1))
// 期望容量大于当前容量的两倍
sli1 = append(sli1, []int{2, 3, 4}...)
fmt.Printf("len=%d cap=%d\n", len(sli1), cap(sli1))
// 如果当前切片的容量小于阈值(默认 256)就会将容量翻倍
sli1 = append(sli1, 1)
fmt.Printf("len=%d cap=%d\n", len(sli1), cap(sli1))
// 如果当前切片的容量大于等于阈值(默认 256),就会每次增加 25% 的容量
/*
//从小切片的2倍生长过渡
//大切片生长1.25倍
newcap += (newcap + 3*threshold) / 4
*/
sli2 := make([]int, 256, 256)
fmt.Printf("len=%d cap=%d\n", len(sli2), cap(sli2))
sli2 = append(sli2, 1)
fmt.Printf("len=%d cap=%d\n", len(sli2), cap(sli2))
for i := 0; i < 10; i++ {
sli2 = append(sli2, sli2...)
fmt.Printf("len=%d cap=%d\n", len(sli2), cap(sli2))
}
}
runtime/slice
go
type slice struct {
array unsafe.Pointer
len int
cap int
}
func growslice(et *_type, old slice, cap int) slice {
if raceenabled {
callerpc := getcallerpc()
racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, abi.FuncPCABIInternal(growslice))
}
if msanenabled {
msanread(old.array, uintptr(old.len*int(et.size)))
}
if asanenabled {
asanread(old.array, uintptr(old.len*int(et.size)))
}
if cap < old.cap {
panic(errorString("growslice: cap out of range"))
}
if et.size == 0 {
// append should not create a slice with nil pointer but non-zero len.
// We assume that append doesn't need to preserve old.array in this case.
return slice{unsafe.Pointer(&zerobase), old.len, cap}
}
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
const threshold = 256
if old.cap < threshold {
newcap = doublecap
} else {
// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for 0 < newcap && newcap < cap {
// Transition from growing 2x for small slices
// to growing 1.25x for large slices. This formula
// gives a smooth-ish transition between the two.
newcap += (newcap + 3*threshold) / 4
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= 0 {
newcap = cap
}
}
}