27、Go 复合数据类型 - 内置函数 make & 切片中使用 make
hi,我是温新
make 函数用途
内置函数 make()
用于为 slice
、map
、channel
类型分配内存和初始化一个对象。
make 函数语法
// 格式
make(type,len,cap)
1、type:数据类型,必填参数。type 的值只能是 slice、map、channel;
2、len:数据类型实际占用的内存空间长度,slice 是必填参数,map 和 channel 是可选参数;
3、cap:容量,为数据类型提前预留的内存空间长度,是一个可选参数。
make 三种不同用法
// 方式一
make(map[string|string])
// 方式二
make([]int, 2)
// 方式三
make([]int, 2, 4)
方式一:只传类型,不指定实际占用的内存空间和提前预留的内存空间,适用于 map 和 channel;
方式二:指定实际占用的内存空间为 2,不指定提前预留的内存空间;
方式三:指定实际占用的内存空间为 2,指定提前预留的内存空间 为 4。
为什么要提前预留空间?
make()
使用的是动态数组算法,一开始向操作系统申请一小块内存 cap,等到 cap 被 len 占满后就需要扩容,而扩容就是动态数组再去向操作系统申请当前长度的两倍的内存,然后将旧数据复制到新的内存空间中。
切片中使用 make
切片中为什么使用 make?
看一个案例
package main
import "fmt"
func main() {
// 声明一个切片
var s []int
fmt.Println(s) // []
s[0] = 100 // 报错
fmt.Println(s)
}
1、声明一个切片,没有赋值,此时内存中并没有开辟一个底层数组出来;
2、因此它打印出来为 []
;
3、对其进行赋值,由于没有开辟出底层数组,因此会报错。
那么,可以这样理解,有一棵树,我用纸写是椅子这个两个,然后贴在树上。如果你要真坐上去,可自然就没有法做了,因为树还没有被加工成椅子。
使用 make
函数相对于就是对这棵树进行加工成椅子,然后就可以坐了。
使用 make 函数
package main
import "fmt"
func main() {
// make 创建一个指定长度和容量的切片
var sli = make([]int, 3, 6)
fmt.Println(sli) // [0 0 0]
// 对指定元素赋值
sli[2] = 100
// 追加元素
sli = append(sli, 200)
fmt.Println(sli)
}
1、使用 make 创建一个长度为 3 ,容量为 6 的切片,此时,会在底层开出一个数组,其容量为 6,但长度为 3,也就是存储的实际值有 3 个,默认为 0 ;
2、因此打印的时候,只会打印出 3 个 0;
3、修改指定元素的值为 100;
4、追加一个元素到切片中,由于提前开辟了预留容量,因此不会动态扩容。
下面是动态扩容案例:
package main
import "fmt"
func main() {
sli := make([]int, 2)
sli[0] = 10
sli[1] = 20
fmt.Printf("长度=%d 容量=%d sli=%v\n", len(sli), cap(sli), sli)
// 追加元素,动态扩容
sli = append(sli, 30, 40, 50)
fmt.Printf("长度=%d 容量=%d sli=%v\n", len(sli), cap(sli), sli)
}
输出结果如下
长度=2 容量=2 sli=[10 20]
长度=5 容量=6 sli=[10 20 30 40 50]