go 切片
1 数据结构
type SliceHeader struct {
Data uintptr // 引用的数组的地址
Len int // 切片长度
Cap int // 引用的数组的长度
}
func TestSlice(t *testing.T) {
// 方式1
slice1 := []int{11, 22, 33, 44, 55}
b := (*reflect.SliceHeader)(unsafe.Pointer(&slice1))
fmt.Println(b.Cap, b.Len) // 5 5
fmt.Println(len(slice1), cap(slice1))
// 方式2
arr := [5]int{11, 22, 33, 44, 55}
slice2 := arr[1:3]
c := (*reflect.SliceHeader)(unsafe.Pointer(&slice2))
// 指向的数组是 arr 从1下标开始的. 所以cap 是4
fmt.Println(c.Cap, c.Len) // 4 2
// slice2[2] 越界了,len是可以访问的范围
// 方式3
slice3 := make([]int, 5)
d := (*reflect.SliceHeader)(unsafe.Pointer(&slice3))
// 5,5,824634322544 data 初始化了, 分配了内存,对应的字节数组元素都是0
fmt.Println(d.Cap, d.Len, d.Data)
slice33 := make([]int, 1, 5)
dd := (*reflect.SliceHeader)(unsafe.Pointer(&slice33))
// cap =5, len=1
fmt.Println(dd.Cap, dd.Len, slice33[0])
// 方式4
var slice4 []int
e := (*reflect.SliceHeader)(unsafe.Pointer(&slice4))
// data 还没有初始化的 ,相比 slice4:=[]int{} 初始化推荐这种
fmt.Println(e.Cap, e.Len, e.Data)
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
// 2个切片引用同一个底层数组
a1 := a[1:4]
a2 := a[2:5]
a1[1] = 111
fmt.Println(a) // 修改了底层数组元素
a2[0] = 222
fmt.Println(a, a1[1])
a1 = append(a1, 333)
fmt.Println(a) // 修改了底层数组元素
}2 append
Tip
- 由于真实的数据是通过引用数组,那么如果追加后长度超过了数组的cap,肯定需要重新分配一块内存,然后还需要将原来的数据复制到新的内存地址上
- 新的内存要多大才好呢?
哪个版本的go 已经忘记了. 后续更新最新版本的
func growslice(et *_type, old slice, cap int) slice {
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
//如果期望容量大于当前容量的两倍就会使用期望容量
newcap = cap
} else {
if old.len < 1024 {
// 否则 如果当前切片的长度小于 1024 就会将容量设置为原先2倍大小
newcap = doublecap
} else {
//如果当前切片的长度大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
if newcap <= 0 {
newcap = cap
}
}
}
}3 遍历 for range
4 增加排序
package main
import (
"fmt"
"math/rand"
"sort"
)
type Student struct {
Name string
Age int
Id string
}
type StudentSlice []Student
// 注意我们是给切片 排序,所以是让切片实现了接口
func (p StudentSlice) Len() int {
return len(p)
}
func (p StudentSlice) Less(i, j int) bool {
return p[i].Name > p[j].Name
}
func (p StudentSlice) Swap(i, j int) {
//这个彼此换,和python一样的写法
p[i], p[j] = p[j], p[i]
}
func main() {
var ss StudentSlice
for i := 0; i < 10; i++ {
s := Student{
Name: fmt.Sprintf("stu%d", rand.Intn(100)),
Id: fmt.Sprintf("ID_%d", rand.Intn(100)),
Age: rand.Intn(100),
}
ss = append(ss, s)
}
for _, v := range ss {
fmt.Println(v)
}
sort.Sort(ss)
fmt.Println("=================")
for _, v := range ss {
fmt.Println(v)
}
}