Go语言中new和make都是用来内存分配的原语(allocation primitives)。简单的说,new只分配内存,make用于slice,map,和channel的初始化。
主要区别于:
- new 给你一个指针,指向零值,适用于 int 型、数组、结构体等值类型。func new(Type) *Type
- make只能用于 slice、map、channel 三种内建引用类型。返回类型本身(非指针)。func make(t Type, size …IntegerType) Type
一、new
1.基本类型(值类型)
一个指针变量声明后为nil,且不可赋值,如下示例:
package main
import (
"fmt"
)
func main() {
var test *int
fmt.Println(test)
}
最终程序返回nil值,nil的值是不能直接赋值的,如果给test赋值,程序报错
package main
import (
"fmt"
)
func main() {
var test *int
fmt.Println(test)
*test = 8
fmt.Println(*test)
}
程序报错:
<nil>
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x104abd7a0]
goroutine 1 [running]:
main.main()
/Users/peter/go/src/go-learning/new/main.go:10 +0x50
exit status 2
如何解决?通过Go提供了new来初始化一地址就可以解决。可以理解为指针变量声明后未分配内存空间,未指向内存地址即nil,进行赋值自然就报错。通过new分配至地址后指针变量指向内存地址,并且初始化zero值
package main
import (
"fmt"
)
func main() {
var test *int
fmt.Println(test)
test = new(int)
fmt.Printf("类型:%T\n", test)
fmt.Println(*test)
*test = 8
fmt.Println(test)
}
程序返回:
<nil>
类型:*int
0
0x1400000e0d8
通过new函数,返回一个指向新分配的类型为int的指针,指针值为0x1400000e0d8,这个指针指向的内容的值为零(zero value)。
同时,需要注意的是不同的指针类型零值是不同的。
2.数组(值类型)
数组类型其实跟基本类型一样,也是值类型,通过new创建与基本类型一样,只不过变成数组指针,并且指向数组首元素地址:
package main
import "fmt"
func main() {
//普通变量
var a int
fmt.Printf("普通变量a: %p %#v \n", &a, a)
var b [5]int
fmt.Printf("普通数组b: %p %#v \n", &b, b)
b[1] = 100
fmt.Printf("普通数组b赋值: %p %#v \n", &b, b)
c := new([5]int)
fmt.Printf("数组指针c: %p %#v \n", &c, c)
(*c)[0] = 8
fmt.Printf("数组指针c赋值: %p %#v \n", &c, c)
fmt.Printf("数组指针c首元素地址: %p %#v \n", &c, (*c)[0])
}
输出结果:
普通变量a: 0x1400000e0d0 0
普通数组b: 0x1400001a240 [5]int{0, 0, 0, 0, 0}
普通数组b赋值: 0x1400001a240 [5]int{0, 100, 0, 0, 0}
数组指针c: 0x14000056038 &[5]int{0, 0, 0, 0, 0}
数组指针c赋值: 0x14000056038 &[5]int{8, 0, 0, 0, 0}
数组指针c首元素地址: 0x14000056038 8
3.引用类型
go会给引用类型初始化为nil,nil是不能直接赋值的。并且不能用new分配内存,示例:
package main
import "fmt"
func main() {
var m map[string]string
fmt.Printf("m: %p %#v \n", &m, m)
mv := new(map[string]string)
fmt.Printf("mv: %p %#v \n", &mv, mv)
(*mv)["a"] = "a"
fmt.Printf("mv: %p %#v \n", &mv, mv)
}
输出报错,new对map并未起到初始化内存作用
m: 0x140000a2028 map[string]string(nil)
mv: 0x140000a2038 &map[string]string(nil)
panic: assignment to entry in nil map
goroutine 1 [running]:
main.main()
/Users/peter/go/src/go-learning/new/main.go:10 +0x148
exit status 2
二、make
那么用make函数处理会是怎么样呢?示例:
package main
import "fmt"
func main() {
// 切片
s := make([]int, 5)
fmt.Printf("切片s: %p %#v %T \n", &s, s, s)
s[0] = 1
fmt.Printf("切片s: %p %#v \n", &s, s)
m := make(map[string]string)
fmt.Printf("字典m: %p %#v %T \n", &m, m, m)
m["m"] = "m"
fmt.Printf("字典m: %p %#v \n", &m, m)
ch := make(chan string)
fmt.Printf("管道ch: %p %#v %T \n", &ch, ch, ch)
go func(message string) {
ch <- message // 存消息
}("Ping!")
fmt.Println(<-ch) // 取消息 //"Ping!"
close(ch)
}
输出
切片s: 0x1400000c018 []int{0, 0, 0, 0, 0} []int
切片s: 0x1400000c018 []int{1, 0, 0, 0, 0}
字典m: 0x14000056038 map[string]string{} map[string]string
字典m: 0x14000056038 map[string]string{"m":"m"}
管道ch: 0x14000056040 (chan string)(0x14000074070) chan string
Ping!
三、总结
- new(T)
- 为类型 T 分配一块 零值内存,返回 *T(指针)。
- 常用于基本类型或结构体。
- 只是简单的内存分配,没有初始化内部数据结构。
- make(T, args)
- 只能用于 slice、map、chan 这三种引用类型。
- 除了分配内存,还会 初始化内部数据结构,并返回 T 本身(不是指针)。
- 为什么?因为这三种类型的底层结构比较复杂,需要额外的元数据管理。



赣ICP备2025054460号-1