【go】make和new

发布于:2025-04-02 ⋅ 阅读:(19) ⋅ 点赞:(0)

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

翻译一下注释内容

  1. 内建函数 make 用来为 slice,map 或 chan 类型(注意:也只能用在这三种类型上)分配内存和初始化一个对象
  2. 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的区别

  1. make 的作用

    • make 是专门为 slice、map 和 channel 设计的,不能用于其他类型(如结构体、数组等)。
    • 它不仅分配内存,还会初始化这些类型的内部数据结构,使其可以直接使用。
  2. new 的作用

    • new 用于分配内存,并将分配的内存初始化为对应类型的零值(zero value),但它不会返回一个已经完全初始化的对象。
    • new 返回的是指向分配内存的指针。
  3. 零值的定义

    • 每种类型的零值是其默认值:
      • 数字类型(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 不仅仅是分配内存,还会初始化对象的内部状态。
  • 对于 slicemake 会将底层数组的元素初始化为零值。
  • 对于 mapmake 会创建一个空的映射,但不会预先填充键值对。
  • 对于 channelmake 会创建一个可用的通道,但不会包含任何数据。

因此,make 的行为可以理解为“初始化为可用状态”,而不是简单地将内存设置为零值。


对比 makenew

特性 make new
适用类型 slice、map、channel 所有类型
返回值 初始化后的值(非指针) 指向零值的指针
是否可直接使用 否(需要进一步初始化)
内部初始化 根据类型特性初始化 仅分配内存并设置为零值(使用还需指向数据)

补充总结

  • make 不会简单地将内存设置为零值,而是根据类型特性进行初始化。
  • 对于 slicemake 会将底层数组的元素初始化为零值。
  • 对于 mapchannelmake 会创建一个可用的空对象。
  • 如果你需要分配内存并设置为零值,请使用 new;如果需要初始化特定类型的对象,请使用 make

网站公告

今日签到

点亮在社区的每一天
去签到