函数 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 分配内置类型和自定义类型

在线运行open in new window启动 AI 助手open in new window

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 提前分配空间

在下运行open in new window启动 AI 助手open in new window

// 每次 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()函数时,切片的容量不足,它将自动重新分配更大的内存空间来存储新元素,并将旧元素复制到新的内存空间中。这种操作的开销比较大,因此在已知切片的长度时,最好预先分配好足够的内存空间。

Last Updated:
Contributors: Bob Wang