Go语言中 new 和 make 的使用及区别 | 豆包MarsCode AI刷题

108 阅读3分钟

在学习 Go 语言时,我们经常会遇到 newmake 关键字。两者虽然都与内存分配相关,但功能和适用场景却截然不同。本笔记旨在整理它们的使用场景及区别,以帮助更好地理解和运用。


new 的使用

概念

  • new(T) 用于分配内存,返回指向类型 T 的指针,并将内存初始化为零值(Zero Value)。

  • 例如数字类型初始化为 0,字符串类型初始化为 ""

使用示例

package main

import "fmt"

func main() {
  foo := new(int)         // 分配内存,返回 *int 类型指针
  fmt.Println(foo)        // 打印内存地址
  fmt.Println(*foo)       // 打印零值 0
  fmt.Printf("%#v", foo)  // 打印变量类型和地址
}

执行结果:

0xc00001a110
0
(*int)(0xc00001a110)

new常见应用场景

初始化结构体

new 常用于初始化结构体,可以快速为结构体分配内存并将字段初始化为零值:

package main

import (
  "bytes"
  "fmt"
  "sync"
)

type SyncedBuffer struct {
  lock   sync.Mutex
  buffer bytes.Buffer
  foo    int
  bar    string
}

func main() {
  p := new(SyncedBuffer)  // 返回 *SyncedBuffer 类型指针
  fmt.Println("foo:", p.foo) // 输出零值 0
  fmt.Println("bar:", p.bar) // 输出零值 ""
  fmt.Printf("%#v\n", p)
}

自定义初始化

new 不能直接设置自定义初始值。如果需要初始化特定值,建议使用以下两种方式:

  1. 直接初始化:

    p := &SyncedBuffer{
      foo: 100,
      bar: "foobar",
    }
    
  2. 通过工厂函数:

    func NewSynced(foo int, bar string) *SyncedBuffer {
      return &SyncedBuffer{
        foo: foo,
        bar: bar,
      }
    }
    
    func main() {
      p := NewSynced(100, "foobar")
      fmt.Println("foo:", p.foo)
      fmt.Println("bar:", p.bar)
    }
    

注意:使用 new 初始化slice、map和channel

new 用于初始化 slicemapchannel 时,返回值为 nil,无法直接使用。例如:

package main

import "fmt"

func main() {
  p := new(map[string]string) // 初始化 map,返回 *map 类型指针
  (*p)["foo"] = "bar"         // panic: assignment to entry in nil map
}

make 的使用

概念

  • make 用于分配和初始化 slicemapchannel
  • new 不同,make 返回的不是指针,而是类型本身。

使用示例

以下示例展示了 newmake 初始化 map 的区别:

package main

import "fmt"

func main() {
  // 使用 new
  var p *map[string]string
  p = new(map[string]string)
  *p = map[string]string{"bar": "foo"} // 手动初始化
  (*p)["foo"] = "bar"
  fmt.Println(*p) // 输出: map[bar:foo foo:bar]

  // 使用 make
  m := make(map[string]string) // 自动初始化
  m["foo"] = "bar"
  m["bar"] = "foo"
  fmt.Println(m) // 输出: map[bar:foo foo:bar]
}

对比:

  • 使用 new 时需要手动分配具体结构(如 map[string]string{})。
  • 使用 make 时可以直接使用初始化后的结构。

newmake 的区别

特性newmake
作用分配内存并返回指针分配内存并初始化类型
返回值指向类型的指针类型本身
适用类型所有类型仅适用于切片(slice)、映射(map)、通道(channel)
零值初始化
初始化结构体字段值不支持不适用
性能优化不适用支持通过设置长度和容量优化性能

  • 使用建议

    • 在初始化 slicemapchannel 时,优先使用 make
    • 若需要获得指针,或用于结构体初始化,考虑使用 new;但若需要自定义初始化值,建议用 &T{} 或工厂函数。