介绍文档用了很多段落来解释new()和make()之间的区别,但实际上,您可以在局部范围内创建对象并返回它们。
为什么要使用这对分配器?
介绍文档用了很多段落来解释new()和make()之间的区别,但实际上,您可以在局部范围内创建对象并返回它们。
为什么要使用这对分配器?
当前回答
除了在Effective Go中解释的所有内容外,new(T)和&T{}之间的主要区别是后者显式执行堆分配。但是,应该注意的是,这取决于实现,因此可能会发生变化。
比较make和new没有什么意义,因为两者执行完全不同的功能。但这在链接的文章中有详细的解释。
其他回答
“make”的好处在其他答案中有很多,但是“New”比上面没有提到的make有一个额外的好处:泛型(截至1.18)。
假设你有一组平面(所有字段都是原语)结构体,如下所示:
type SomeStruct struct {
V1 string `json:"v1"`
V2 string `json:"v2"`
}
你想要创建一个映射函数,将一个map[string]字符串转换为任何结构体。然后你可以这样写:
func GetStructFromMap[T any](values map[string]string) (T, error) {
myStr := T{}
bytes, err := json.Marshal(values)
if err != nil {
return *myStr, err
}
if err := json.Unmarshal(bytes, str); err != nil {
return *myStr, err
}
return *myStr, nil
}
但是,这段代码将抛出一个关于myStr:= T{}行的错误,关于无效的组合值。用myStr:= make(T)替换它会产生另一个关于没有底层类型的错误。因此,您需要将该行替换为myStr:= new(T),这将创建一个对该结构的零值实例的引用。
可以看到,在处理泛型时,new可以用来实例化编译时未知的类型。
另一方面,在这个特定的示例中还可以使用命名返回类型,但更普遍的用法仍然有效。
你能用它做的事情用其他方法做不到:
创建通道 创建一个预分配空间的映射 创建一个预先分配空间的切片,或者使用len != cap
要证明新的合理性有点难。它简化的主要事情是创建指向非复合类型的指针。 下面两个函数是等价的。一个更简洁一点:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
除了在Effective Go中解释的所有内容外,new(T)和&T{}之间的主要区别是后者显式执行堆分配。但是,应该注意的是,这取决于实现,因此可能会发生变化。
比较make和new没有什么意义,因为两者执行完全不同的功能。但这在链接的文章中有详细的解释。
new(T):它返回一个指向类型T的指针,一个类型为*T的值,它分配并归零内存。new(T)等价于&T{}。
make(T):返回类型为T的初始化值,分配并初始化内存。它用于切片,映射和通道。
您需要make()来创建通道和映射(以及切片,但这些也可以从数组创建)。没有其他方法来创建这些,所以不能从词典中删除make()。
至于new(),当可以使用结构语法时,我不知道为什么还需要它。但它确实有一个独特的语义含义,即“创建并返回一个将所有字段初始化为零值的结构体”,这很有用。