new 和 make 的区别
# make 和 new 的区别
# new
# 函数签名
new
的函数签名:
func new(Type) *Type
1
参数说明:
Type
:需要new
的类型。- 返回值是指向
Type
的指针,新分配的值为Type
的零值。
# 作用
new
主要用于分配内存, 但与其它语言中的同名函数不同,它不会初始化内存,只会将内存置零。 也就是说,new(T)
会为类型为T
的新项分配已置零的内存空间, 并返回它的地址(即*T
)。用 Go 的术语来说,它返回一个指针, 该指针指向新分配的,类型为T
的零值。
例如下面这个例子,i
是一个int
类型的指针,但是没有分配内存空间,因此是不能赋值的。执行这个测试会报错:invalid memory address or nil pointer dereference
。
/*
TestVariable 会报错
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4f503b]
*/
func TestVariable(t *testing.T) {
var i *int
*i = 10
t.Log(*i)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
现在使用new
来分配内存:
func TestNew_int(t *testing.T) {
var i *int
i = new(int)
fmt.Println(*i) // 0 提示:int 的零值为 0
*i = 1
fmt.Println(*i) // 1
}
1
2
3
4
5
6
7
2
3
4
5
6
7
现在重新执行这个测试,可以通过了。
# make
# 函数签名
make
的函数签名:
func make(t Type, size ...IntegerType) Type
1
make
和new
一样,第一个参数是一个类型,而不是一个值。与new
不同的是,make
的返回类型与其参数的类型相同,而不是指向它的指针。
# 作用
make
不同于new
,它仅限于slice
、map
和chan
的初始化(分配内存空间,而非置零),同时它接收三个参数。第一个参数是类型,第二个是该类型的长度,第三个是该类型的容量。出现这种用差异的原因在于,这三种类型本质上为引用数据类型,它们在使用前必须初始化。
注意:如果第一个参数是map
类型,那么make
只接收两个参数,第二个是容量。
下面这个例子是创建一个长度为0,容量为10的int
类型的切片(slice
):
func TestMake_slice(t *testing.T) {
l := make([]int, 0, 10)
fmt.Println(l == nil) // false
fmt.Printf("len: %d cap: %d\n", len(l), cap(l)) // len: 0 cap: 10
l = append(l, 1)
fmt.Println(l) // [1]
}
1
2
3
4
5
6
7
2
3
4
5
6
7
使用new
来创建的切片并不能指定长度和容量,返回的是指向切片的指针:
func TestNew_slice(t *testing.T) {
l := new([]int)
fmt.Println(*l == nil) // true
fmt.Printf("len: %d cap: %d\n", len(*l), cap(*l)) // len: 0 cap: 0
*l = append(*l, 1)
fmt.Println(*l) // [1]
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# new
与make
的异同
# 相同点
new
和make
都是用于给指定的类型分配内存空间。
# 不同点
make
仅限于slice
、map
和chan
的初始化。make
接收的参数比new
多,它的返回值是slice
、map
或chan
这个三个类型本身,而不是它们的指针类型,因为这三种就是引用类型。new
用于类型内存分配(初始化值为类型的零值),返回值是指向Type
的指针。
提示:不要使用new
,永远用 make
来构造 map
。如果你错误的使用new
分配了一个引用对象,你会获得一个空引用的指针,相当于声明了一个未初始化的变量并且取了它的地址:
func TestNew_map(t *testing.T) {
m := new(map[string]int)
fmt.Println(*m == nil) // true
(*m)["key"] = 1 // panic: assignment to entry in nil map
}
1
2
3
4
5
2
3
4
5
上次更新: 2024/05/29, 06:25:22