介绍文档专门用许多段落来解释new()
和make()
之间的区别,但在实践中,您可以在局部范围内创建对象并返回它们。
为什么要使用这对分配器?
答案 0 :(得分:140)
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
和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
似乎更合适。
答案 1 :(得分:137)
你可以用make
做的事情,你不能做任何其他事情:
证明new
是合理的。它更容易的主要是创建指向非复合类型的指针。
以下两个功能是等效的。一个更简洁:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
答案 2 :(得分:19)
make function仅分配和初始化slice,map或chan类型的对象。像new一样,第一个参数是一个类型。但是,它也可以采取第二个论点,即大小。与new不同,make的返回类型与其参数的类型相同,而不是指向它的指针。并且初始化分配的值(不像新的那样设置为零值)。 原因是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
答案 3 :(得分:8)
除Effective Go中解释的所有内容外,new(T)
和&T{}
之间的主要区别在于后者显式执行堆分配。但是应该注意,这是依赖于实现的,因此可能会有所变化。
将make
与new
进行比较毫无意义,因为两者执行完全不同的功能。但这在链接文章中有详细解释。
答案 4 :(得分:6)
您需要make()
来创建频道和地图(和切片,但也可以从数组创建)。没有替代方法可以制作这些内容,因此您无法从词典中删除make()
。
至于new()
,当你可以使用struct语法时,我不知道为什么你需要它。它确实有一个独特的语义含义,即“创建并返回一个结构,所有字段都初始化为零值”,这可能很有用。
答案 5 :(得分:4)
new(T):它返回一个指向类型T 的指针,类型为* T,它分配并清零内存。 new(T)相当于& T {} 。
make(T):它返回一个类型为T 的初始值,它分配并初始化内存。它用于切片,地图和通道。
答案 6 :(得分:4)
换句话说,新分配; make 初始化;
var p *[]int = new([]int)
or
// *p == nil; with len and cap 0
p := new([]int)
这很少有用。
p := make([]int, 0)
我们的切片已初始化,但这里指向一个空数组。
这两个语句都不是很有用,以下是:
var v []int = make([]int, 10, 50)
// Or
v := make([]int, 10, 50)
这将分配一个包含 50 个整数的数组,然后创建一个长度为 10、容量为 50 的切片 v,指向数组的前 10 个元素。
package main
type Foo map[string]string
type Bar struct {
s string
i int
}
func main() {
// OK:
y := new(Bar)
(*y).s = "hello"
(*y).i = 1
// NOT OK:
z := make(Bar) // compile error: cannot make type Bar
z.s = "hello"
z.i = 1
// OK:
x := make(Foo)
x["x"] = "goodbye"
x["y"] = "world"
// NOT OK:
u := new(Foo)
(*u)["x"] = "goodbye" // !!panic!!: runtime error:
// assignment to entry in nil map
(*u)["y"] = "world"
}
频道:
func main() {
// OK:
ch := make(chan string)
go sendData(ch)
go getData(ch)
time.Sleep(1e9)
// NOT OK:
ch := new(chan string)
go sendData(ch) // cannot use ch (variable of type *chan string)
// as chan string value in argument to sendData
go getData(ch)
time.Sleep(1e9)
}
func sendData(ch chan string) {
ch <- "Washington"
ch <- "Tripoli"
ch <- "London"
ch <- "Beijing"
ch <- "Tokio"
}
func getData(ch chan string) {
var input string
for {
input = <-ch
fmt.Printf("%s ", input)
}
}
答案 7 :(得分:3)
new(T)
-分配内存,并将其设置为 T 类型的零值。.
..即 int 的0
, string 的""
和引用类型( slice ,地图, chan )
请注意,引用的类型只是指向某些基础数据结构的指针,这些数据结构不会由nil
创建
示例:如果是 slice ,则不会创建基础的 array ,因此new(T)
返回不指向任何内容的指针
new([]int)
-为引用的数据类型(切片,地图, chan )和分配内存>初始化其基础数据结构
示例:对于 slice ,将以指定的长度和容量创建基础的 array
请记住,与C不同,数组是Go中的原始类型!
话虽这么说
make(T)
的行为类似于复合文字语法
make(T)
的行为类似于new()
(未初始化变量时)
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)
}
进一步阅读:
https://golang.org/doc/effective_go.html#allocation_new
https://golang.org/doc/effective_go.html#allocation_make
答案 8 :(得分:1)
已经有很多好的答案,但让我解释一下 new() 和 make() 作为单独分配器的必要性。
当 new() 需要处理其他三种复合类型 - chan、slice 和 map 时,就会出现问题。 这三种类型本质上是特殊的,它们的底层类型不仅仅是另一种类型,而是需要初始化的状态。例如,切片的底层状态由指向内部数组存储的第一个元素的指针、确定可以访问的元素数量的长度以及随着元素数量增加而增加的容量组成。 new() 肯定无法处理此类类型的分配,因为它们需要额外的初始化步骤,这就是 make() 发挥作用的地方。