函数 make 签名
func make(t Type, size ...IntegerType) Type
函数 new 签名
func new(Type) *Type
从函数签名上可以看到 make 返回类型 Type,而 new 返回指向 Type 的指针,make 只能用于 slice、map、channel 的初始化,new 可以分配任意类型(包括自定义类型)的数据,make 分配的空间会进行初始化,new 分配的空间会进行清零。
使用 new 分配内置类型和自定义类型
func createBuiltType() *int {
return new(int)
}
type person struct {
RealName string
}
func createCustomType() *person {
p := new(person)
return p
}
func main() {
intObject := createBuiltType()
*intObject = 100
fmt.Println(*intObject)
personObject := createCustomType()
personObject.RealName = "zhangsan"
fmt.Println(*personObject)
}
代码定义了两个函数:createBuiltType()和createCustomType(),分别用于创建内置类型(int)和自定义类型(person)的指针。其中,createBuiltType()使用new()函数创建了一个int类型的指针,而createCustomType()则使用new()函数创建了一个person类型的指针。
在main()函数中,首先调用createBuiltType()函数创建一个int类型的指针intObject,然后将该指针所指向的变量赋值为100。接着,调用createCustomType()函数创建一个person类型的指针personObject,并将该指针所指向的RealName字段赋值为"zhangsan"。最后,使用fmt.Println()函数输出intObject和personObject指针所指向的变量的值。
需要注意的是,在输出personObject指针所指向的变量的值时,代码使用了*personObject来取得该指针所指向的实际值,但是这个值是一个person类型的结构体,而不是字符串。因此,代码应该修改为fmt.Println(personObject.RealName)才能输出正确的值。
make 提前分配空间
// 每次 append 都会判断是否需要扩容
func unorderKeys1(m map[string]int) []string {
// 这里不用 make 也行
// var keys []string
keys := make([]string, 0)
for k := range m {
keys = append(keys, k)
}
return keys
}
// 提前知道了需要的空间,可预先分配好
func unorderKeys2(m map[string]int) []string {
keys := make([]string, len(m))
index := 0
for k := range m {
// 常见错误:
// 预先分配的情况下是用 append 继续追加空间
// keys = append(keys, k)
keys[index] = k
index++
}
return keys
}
代码定义了两个函数unorderKeys1()和unorderKeys2(),它们的作用是获取一个无序映射map类型的所有键,并将这些键存储在一个字符串切片中返回。
unorderKeys1()函数使用了make()函数创建了一个初始长度为0的字符串切片keys,并通过for循环遍历映射中的所有键,并将它们依次添加到keys中。最后,返回keys切片。
unorderKeys2()函数与unorderKeys1()函数类似,不同之处在于它预先知道了映射的大小,因此可以在创建keys切片时一次性分配好所需的内存空间。这样做可以避免append()函数因为空间不足而频繁重新分配内存的开销。在循环遍历映射中的键时,代码使用一个index变量来记录当前需要添加到keys切片的位置,并直接将键值赋值给keys切片中相应位置的元素,避免了使用append()函数的开销。最后,返回keys切片。
需要注意的是,在使用make()函数创建切片时,如果不指定长度,它将创建一个长度为0的切片。如果在使用append()函数时,切片的容量不足,它将自动重新分配更大的内存空间来存储新元素,并将旧元素复制到新的内存空间中。这种操作的开销比较大,因此在已知切片的长度时,最好预先分配好足够的内存空间。