make和new
1. new 函数
在官方文档中,new 函数的描述如下
// The new built-in function allocates memory. The first argument is a type,
// not a value, and the value returned is a pointer to a newly
// allocated zero value of that type.
func new(Type) *Type
可以看到,new 只能传递一个参数,该参数为一个任意类型,可以是Go语言内建的类型,也可以是你自定义的类型
那么 new 函数到底做了哪些事呢:
- 分配内存
- 设置零值(设置对应类型的零值)
- 返回指针(重要)
举个例子
package main
import "fmt"
type Student struct {
name string
age int
}
func main() {
// new 一个内建类型
num := new(int)
fmt.Println(*num) //打印零值:0
// new 一个自定义类型
s := new(Student)
s.name = "wangbm"
// 字符串只能和字符串相“+”
fmt.Println(s.name+" "+fmt.Sprint(s.age)) //打印零值:wangbm 0
}
2. make 函数
在官方文档中,make 函数的描述如下
//The make built-in function allocates and initializes an object
//of type slice, map, or chan (only). Like new, the first argument is
// a type, not a value. Unlike new, make's return type is the same as
// the type of its argument, not a pointer to it.
func make(t Type, size ...IntegerType) Type
翻译一下注释内容
- 内建函数 make 用来为 slice,map 或 chan 类型(注意:也只能用在这三种类型上)分配内存和初始化一个对象
- make 返回类型的本身,而不是指针,而返回值也依赖于具体传入的类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了
注意,因为这三种类型是引用类型,所以必须得初始化(size和cap),但不是置为零值,这个和new是不一样的。
举几个例子
注意切片的make中,必须给第二个参数,表示切片的长度
package main
import "fmt"
func main() {
//切片
a := make([]int,0)
// 字典
b := make(map[string]int)
// 通道
c := make(chan int, 10)
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
输出结果:可以看到没有设置零值
[]
map[]
0xc000082000
3. 总结
new:为所有的类型分配内存,并初始化为零值,返回指针。
make:只能为 slice,map,chan 分配内存,并初始化,返回的是类型。
另外,目前来看 new 函数并不常用,大家更喜欢使用短语句声明的方式。
a := new(int)
*a = 1
// 等价于
a := 1
但是 make 就不一样了,它的地位无可替代,在使用slice、map以及channel的时候,还是要使用make进行初始化,然后才可以对他们进行操作。
在 Go 中,make
函数用于初始化 slice、map 和 channel 这三种特殊的内置类型。它会为这些类型分配内存,并根据类型的不同进行一些初始化操作。然而,make
的行为与 new
不同:make
不仅仅是分配内存,还会对分配的内存进行适当的初始化。
补充
make
和new的区别
make
的作用make
是专门为 slice、map 和 channel 设计的,不能用于其他类型(如结构体、数组等)。- 它不仅分配内存,还会初始化这些类型的内部数据结构,使其可以直接使用。
new
的作用new
用于分配内存,并将分配的内存初始化为对应类型的零值(zero value),但它不会返回一个已经完全初始化的对象。new
返回的是指向分配内存的指针。
零值的定义
- 每种类型的零值是其默认值:
- 数字类型(
int
,float64
等):0
- 布尔类型(
bool
):false
- 字符串(
string
):空字符串""
- 指针(
*T
):nil
- 切片(
slice
)、映射(map
)、通道(channel
):nil
- 数字类型(
- 每种类型的零值是其默认值:
make
是否会设置零值?
make
并不会简单地将内存设置为零值,而是根据类型的不同,初始化其内部状态,使其可以安全地使用。具体来说:
1. Slice
使用
make([]T, length, capacity)
创建一个切片时:length
表示切片的长度。capacity
表示底层数组的容量。
make
会分配一个底层数组,并将其元素初始化为对应类型的零值。示例:
s := make([]int, 3) // 创建一个长度为 3 的切片 fmt.Println(s) // 输出:[0 0 0]
- 底层数组的每个元素都被初始化为
int
类型的零值0
。
- 底层数组的每个元素都被初始化为
2. Map
使用
make(map[K]V)
创建一个映射时:make
会分配一个空的哈希表,但不会预先填充任何键值对。- 映射本身是空的,但它已经可以安全地存储键值对。
示例:
m := make(map[string]int) fmt.Println(m) // 输出:map[]
3. Channel
使用
make(chan T, buffer)
创建一个通道时:- 如果指定了缓冲区大小(
buffer > 0
),make
会创建一个带缓冲的通道。 - 如果未指定缓冲区大小(
buffer = 0
),make
会创建一个无缓冲的通道。
- 如果指定了缓冲区大小(
示例:
ch := make(chan int, 2) // 创建一个带缓冲的通道 fmt.Println(ch) // 输出:chan
make
和零值的关系总结
make
不仅仅是分配内存,还会初始化对象的内部状态。- 对于 slice,
make
会将底层数组的元素初始化为零值。 - 对于 map,
make
会创建一个空的映射,但不会预先填充键值对。 - 对于 channel,
make
会创建一个可用的通道,但不会包含任何数据。
因此,make
的行为可以理解为“初始化为可用状态”,而不是简单地将内存设置为零值。
对比 make
和 new
特性 | make |
new |
---|---|---|
适用类型 | slice、map、channel | 所有类型 |
返回值 | 初始化后的值(非指针) | 指向零值的指针 |
是否可直接使用 | 是 | 否(需要进一步初始化) |
内部初始化 | 根据类型特性初始化 | 仅分配内存并设置为零值(使用还需指向数据) |
补充总结
make
不会简单地将内存设置为零值,而是根据类型特性进行初始化。- 对于 slice,
make
会将底层数组的元素初始化为零值。 - 对于 map 和 channel,
make
会创建一个可用的空对象。 - 如果你需要分配内存并设置为零值,请使用
new
;如果需要初始化特定类型的对象,请使用make
。