Go 语言提供了 new () 和 make () ,该如何选择?

Go

这是有关 Go 内置函数 makenew 的帖子。

正如 Rob Pike 在今年 Gophercon 上指出的那样,Go 有许多初始化变量的方法。其中之一就是能够获取 struct literal 地址的能力,这将导致实现相同操作的多种方法。

s := &SomeStruct{}
v := SomeStruct{}
s := &v              // 相同
s := new(SomeStruct) // 也相同

公平的是,评论者指出了这种语言上的冗余,有时这会导致他们搜索其他不一致之处,最显着的是 makenew 之间的冗余。

从表面上看,makenew 做的事情非常相似,那么两者并存的理由是什么?

为什么我们不能对任何事物都使用 make ?

Go 没有用户定义的泛型类型,但是确实有几种内置类型可以用作泛型,lists(列表),maps(映射),sets(集合) 和 queues(队列);(slices)切片,maps(映射)和 channels(通道)。

由于 make 旨在创建这三种内置泛型类型,因此必须由运行时提供,因为无法在 Go 中直接表达make 的功能签名。

尽管 make 创建了泛型切片,映射和通道值,但它们仍然只是常规值; make 不返回指针值。

如果为有利于 make 而删除 new,您将如何构造指向初始值的指针?

var x1 *int
var x2 = new(int)

x1x2 具有相同的类型,*intx2 指向初始化的内存,并且可以安全地取消引用,相同的是对于 x1 都不为 true。

为什么我们不能对任何事物都使用 new ?

尽管 new 很少使用,但其行为已经被很好地指定了。

new(T) 始终返回一个 * T 指向已初始化的T。由于 Go 没有构造函数,因此该值将被初始化为T零值

使用 new 构造指向切片,映射或通道零值的指针,目前可以使用并且与 new 的行为一致。

s := new([]string)
fmt.Println(len(*s))  // 0
fmt.Println(*s == nil) // true

m := new(map[string]int)
fmt.Println(m == nil) // false
fmt.Println(*m == nil) // true

c := new(chan int)
fmt.Println(c == nil) // false
fmt.Println(*c == nil) // true

当然可以,这些只是规则,我们可以更改它们,对吧?

对于它们可能造成的混乱,makenew是一致的;make仅创建切片,映射和通道,new仅返回指向初始化内存的指针。

是的,对于切片,映射和通道,new 可以扩展为像 make 一样运行,但这会引入自身的不一致之处。

  1. 如果传递给 new 的类型是一个切片,映射或 通道,则 new 将具有特殊的行为。这是每个 Go 程序员都必须记住的规则。
  2. 对于切片和映射,new 必须变得可变,并根据需要采用可能的长度,缓冲区大小或容量。再次需要记住更多的特殊情况,而在 new 之前,只有一个参数,即类型。
  3. new 始终为传递给它的 T 返回一个 *T。那意味着代码像
func Read(buf []byte) []byte
// 假设 new 需要一个可选的长度
buf := Read(new([]byte, 4096))

这样的代码将不再可能,需要在语法中使用更多特殊情况才能允许 *new([]byte,length)

综上所述

makenew 做不同的事情。

如果您是从另一种语言转过来的,尤其是使用构造函数的语言,那么看来 new 应该是您所需要的,但是 Go 并不是那些语言,也没有构造函数。

我的建议是尽量保守地使用 new,因为不用它,几乎总是有更简单或更干净的方法来编写程序。

作为代码审查者,使用 new 就像使用命名返回参数一样,表明该代码正在尝试做一些聪明的事情,我需要特别注意。可能代码确实很聪明,但更可能的是,它可以重写得更清楚、更符合习惯。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://dave.cheney.net/2014/08/17/go-ha...

译文地址:https://learnku.com/go/t/47215

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!