Go 有一个特殊的 make
函数,可用于初始化通道、切片和映射。
使用 make
,我们可以指定正在创建的数据类型的内存和容量限制,为我们提供使用常规构造函数无法实现的低级别控制。
基本用法
make
是 Go 中的一个特殊函数,它可以接受不同数量的类型和参数。
它将返回第一个参数指定的类型的实例:
obj := make(someType, optionalArgument1, optionalArgument2)
在这里,someType
可以是切片、映射或通道。
创建切片
我们可以使用 make
初始化任何类型的切片:
words := make([]string, 2)
这里,第一个参数是类型,第二个参数是长度。
默认情况下,一个新切片被初始化并填充与指定长度一样多的空值。
因此,在这种情况下,words
的值将是 []string{"", ""}
我们还可以在创建切片时传递第三个参数,即容量。容量表示分配给一个切片的内存量,即使它的长度可能没有那么多。
例如,如果我们也使用容量来创建 words
:
words := make([]string, 2, 5)
容量参数必须大于长度参数,否则代码将无法构建
words
的值现在仍然是 []string{"", ""}
,但是底层内存被分配给 5 个字符串值。
len=2 cap=5
|""|""|X|X|X|
因此,如果我们使用 append
添加另一个元素,Go 不会在后台分配更多内存:
words = append(words, "axiaoxin blog")
默认情况下,如果你不分配任何容量,Go 会采用默认容量。添加更多列表元素时,Go 会在需要时提供更多容量。
因此,如果你事先知道切片的大小,那么指定容量就非常有用,因为每次超过默认容量时我们都可以跳过额外的分配。
请注意,指定容量并没有限制最大限制,而是规定了在添加更多元素时需要重新分配的初始容量
创建映射
将 make
与 maps 一起使用并不像 slice 那样简单。
// make 一个空 map
m := make(map[int]string)
// make 一个 n 个元素的 map
m := make(map[int]string, n)
我们依旧可以 make 空的 map 实例,并指定容量,但是这里的容量是一个语言上的示意,并不对分配的确切容量做出任何保证。
Golang 语言规范提到第二个参数是指“大约 n 个元素的初始空间”
创建通道
我们可以使用 make 创建不同类型的通道:
- 无缓冲通道,不能存储任何数据,只能充当数据管道:
// 创建一个无缓冲的整数通道 out := make(chan int)
- 可以存储一定数量数据的缓冲通道
// 创建一个缓冲通道,最多可以容纳 3 个整数值 out := make(chan int, 3)
make 与 new 的区别
Go 还有一个内置函数 new
,它经常出现在与 make
类似的场景中,但具有不同的功能。
make
能够分配变量内存并返回所提供类型的实例,而 new 只能初始化空实例,并返回所提供参数的指针。
让我们看一个例子:
// 返回一个包含 1 个默认 (0) int 元素的切片
s1 := make([]int, 1)
// 返回一个指向空切片的指针
s2 := new([]int)
fmt.Println(s1)
fmt.Println(s2)
如果我们运行这段代码,我们将得到:
[0]
&[]
总结
make
是一个多功能的内置函数,可用于初始化不同的数据类型。
参数及其意义取决于被初始化的变量类型。
可以在Golang语言规范中阅读更多有关 make
和 new
如何工作的详细信息。