make
用于分配并初始化的工具。专门用来创建并初始化 slice、map、channel,返回值本身(不是指针)。针对于不同的类型帮用户在底层做一些事情
go
// slice:长度5,容量10(已初始化为零值)
orders := make([]string, 5, 10)
// map:可以直接往里面塞东西
menu := make(map[string]float64)
menu["红烧肉"] = 38.5
// channel:无缓冲
ch := make(chan int)
// 有缓冲,容量3
bufferedCh := make(chan int, 3)
make只用于这三种类型,别的类型用不了
new
分配一块内存,填上零值,返回指向它的指针(*T)
go
p := new(int)
// p 是 *int,指向 0
*p = 42通常直接用 &T{} 更常见,比如 s := &Student{},new 基本只在很底层或特殊场合出现
append
向 slice(切片) 尾部追加元素,返回新的 slice(因为扩容换了底层数组)
go
dishes := []string{"红烧肉"}
dishes = append(dishes, "清蒸鱼", "西红柿炒蛋")
// dishes 现在是 ["红烧肉", "清蒸鱼", "西红柿炒蛋"]扩容规则(大致):旧容量小于 256 时,扩容为原来的两倍左右;之后按一定比例增长,减少内存浪费
最佳实践:
- 一定要用变量接收返回值,
append返回新的 slice 头 - 若预先知道大致元素数量,用
make([]T, 0, cap)预分配容量,避免反复扩容
copy
把源 slice 的元素拷贝到目标 slice,返回实际拷贝的元素数(取两者最小长度)
go
src := []int{1, 2, 3, 4}
dst := make([]int, 2)
n := copy(dst, src)
// dst = [1, 2]; n = 2一般用于深拷贝 slice 底层数据;不改变原 slice 的 capacity 情况下的安全复制
len&cap
len(v):求长度(slice 里现有多少数据,map 里多少键值对,channel 里缓冲了多少元素)
cap(v):求容量(slice 底层数组总长度,channel 的缓冲总格数)
go
s := make([]int, 3, 5)
fmt.Println(len(s)) // 3
fmt.Println(cap(s)) // 5delete
从 map 中删除给定的键
go
menu := map[string]float64{"红烧肉": 38.5}
delete(menu, "红烧肉")close
关闭一个 channel,表示不再发送数据
关闭后:
- 接收方可以继续读取已缓冲的数据,读完后得到零值,
ok为false - 往已关闭的 channel 发送数据会 panic
go
ch := make(chan int, 2)
ch <- 1
close(ch)
v, ok := <-ch // 1, true
v, ok = <-ch // 0, false