Answers:
您可以做的事情make
,您无法做其他任何事情:
证明有一点困难new
。使它变得更容易的主要事情是创建指向非复合类型的指针。以下两个功能是等效的。简而言之:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
m := map[string]int{}
,而不是m := make(map[string]int)
?也不需要预先分配大小。
Go具有多种内存分配和值初始化方式:
&T{...}
,&someLocalVar
,new
,make
创建复合文字时也可能发生分配。
new
可以用来分配整数等值,&int
是非法的:
new(Point)
&Point{} // OK
&Point{2, 3} // Combines allocation and initialization
new(int)
&int // Illegal
// Works, but it is less convenient to write than new(int)
var i int
&i
通过查看以下示例new
,make
可以看到和之间的区别:
p := new(chan int) // p has type: *chan int
c := make(chan int) // c has type: chan int
假设Go没有new
and make
,但是它具有内置功能NEW
。然后,示例代码将如下所示:
p := NEW(*chan int) // * is mandatory
c := NEW(chan int)
这*
将是强制性的,因此:
new(int) --> NEW(*int)
new(Point) --> NEW(*Point)
new(chan int) --> NEW(*chan int)
make([]int, 10) --> NEW([]int, 10)
new(Point) // Illegal
new(int) // Illegal
是的,合并new
和make
成一个单一的内置功能是可能的。但是,与具有两个内置函数相比,单个内置函数可能会在新的Go程序员中引起更多的混乱。
考虑到以上所有方面,似乎更适合new
并将make
其分开。
int
是创建的实例。
make(Point)
和make(int)
上面提到的最后两行?
make
函数仅分配和初始化slice,map或chan类型的对象。像一样new
,第一个参数是一个类型。但是,它也可能需要第二个参数,即大小。与new不同,make的返回类型与其参数的类型相同,而不是指向它的指针。并且分配的值被初始化(不像new中那样设置为零值)。原因是slice,map和chan是数据结构。它们需要初始化,否则将无法使用。这就是new()和make()需要不同的原因。
以下来自Effective Go的示例非常清楚:
p *[]int = new([]int) // *p = nil, which makes p useless
v []int = make([]int, 100) // creates v structure that has pointer to an array, length field, and capacity field. So, v is immediately usable
new([]int)
,它只是为[] int分配内存,但没有初始化,因此它仅返回nil
; 不是指向内存的指针,因为它不可用。make([]int)
分配并初始化,使其可用,然后返回其地址。
new(T)
-分配内存,并将其设置为在零值类型Ť ..
..that是0
为INT,""
对字符串和nil
用于被引用类型(切片,地图,CHAN)
请注意,引用的类型只是指向某些基础数据结构的指针,
示例将不会创建这些数据结构new(T)
:如果为slice,则不会创建基础数组,因此new([]int)
返回的指针为空
make(T)
-为引用的数据类型(slice,map,chan)分配内存,并初始化其基础数据结构
示例:如果是slice,则将使用指定的长度和容量创建基础数组
。请记住,与C不同,数组是Go!中的原始类型!
话虽如此:
make(T)
表现像复合文字语法
new(T)
行为类似var
(未初始化变量时)
func main() {
fmt.Println("-- MAKE --")
a := make([]int, 0)
aPtr := &a
fmt.Println("pointer == nil :", *aPtr == nil)
fmt.Printf("pointer value: %p\n\n", *aPtr)
fmt.Println("-- COMPOSITE LITERAL --")
b := []int{}
bPtr := &b
fmt.Println("pointer == nil :", *bPtr == nil)
fmt.Printf("pointer value: %p\n\n", *bPtr)
fmt.Println("-- NEW --")
cPtr := new([]int)
fmt.Println("pointer == nil :", *cPtr == nil)
fmt.Printf("pointer value: %p\n\n", *cPtr)
fmt.Println("-- VAR (not initialized) --")
var d []int
dPtr := &d
fmt.Println("pointer == nil :", *dPtr == nil)
fmt.Printf("pointer value: %p\n", *dPtr)
}
运行程序
-- MAKE --
pointer == nil : false
pointer value: 0x118eff0 # address to underlying array
-- COMPOSITE LITERAL --
pointer == nil : false
pointer value: 0x118eff0 # address to underlying array
-- NEW --
pointer == nil : true
pointer value: 0x0
-- VAR (not initialized) --
pointer == nil : true
pointer value: 0x0
进一步阅读:
https
: //golang.org/doc/effective_go.html#allocation_new https://golang.org/doc/effective_go.html#allocation_make
您需要make()
创建通道和地图(以及切片,但是也可以从数组创建切片)。没有其他方法可以制作这些作品,因此您无法make()
从词典中删除它们。
至于new()
,我不知道有什么理由可以使用struct语法时就需要它。但是,它确实具有独特的语义,即“创建并返回所有字段均初始化为零值的结构”,这很有用。
除了Effective Go中解释的所有内容之外,new(T)
和之间的主要区别在于&T{}
后者明确执行堆分配。但是,应注意,这取决于实现方式,因此可能会发生变化。
比较make
起来new
没有什么意义,因为两者执行的功能完全不同。但这在链接的文章中有详细说明。
&T{}
明确执行堆分配不基于任何规格AFAIK。实际上,我相信转义分析已经尽可能地将与* T相同的方式将* T保留在堆栈中new(T)
。