Go语言中new与make的使用解读

作者:

文章目录
  • 作用: 分配内存。 将分配的内存清零(设置为相应类型的零值)。 返回一个指向新分配的零值 T 的指针 (*T)。 语法: p := new(T) 其中 T 可以是任何类型。 返回值: 一个指向类型 T 的指针 (*T)。 适用类型: 几乎所有类型,包括基本类型(int, string, bool等)、结构体(struct)、数组(array)等。 也可以用于 slice, map, channel,但通常不这么用,因为 new 返回的是指向这些引用类型本身的指针,而引用类型本身在未初始化时是 nil。 示例: // 为 int 分配内存,i 是 *int 类型,*i 的值是 0 var i *int = new(int) fmt.Printf(“i: %p, *i: %dn”, i, *i) // *i 是 0 // 为自定义结构体 MyStruct 分配内存,s 是 *MyStruct 类型 type MyStruct struct { Field1 int Field2 string } var s *MyStruct = new(MyStruct) fmt.Printf(“s: %p, s.Field1: %d, s.Field2: ‘%s’n”, s, s.Field1, s.Field2) // s.Field1 是 0, s.Field2 是 “” // 对于引用类型(不推荐,但可以这么做) var sl *[]int = new([]int) // sl 是 *[]int 类型,*sl 的值是 nil fmt.Printf(“sl: %p, *sl == nil: %tn”, sl, *sl == nil) // *sl 是 nil,无法直接使用 append 等操作 var m *map[string]int = new(map[string]int) // m 是 *map[string]int 类型,*m 的值是 nil fmt.Printf(“m: %p, *m == nil: %tn”, m, *m == nil) // *m 是 nil,无法直接赋值
  • 作用: 仅用于 slice、map 和 channel 这三种内置引用类型的创建。 它不仅分配内存,还会初始化这些类型的内部数据结构,使其立即可用。 语法: Slice: make([]T, length, capacity) 或 make([]T, length) (capacity 默认为 length) Map: make(map[K]V, initialCapacity) 或 make(map[K]V) (initialCapacity 可选) Channel: make(chan T, bufferCapacity) 或 make(chan T) (bufferCapacity 可选,默认为0,即无缓冲) 返回值: 返回的是初始化后的类型 T 本身(例如 []int, map[string]int, chan int),而不是指针。 适用类型: 只能是 slice, map, channel。 示例: // 创建一个长度为 5,容量为 10 的 int 切片 s1 := make([]int, 5, 10) fmt.Printf(“s1: %v, len: %d, cap: %dn”, s1, len(s1), cap(s1)) // s1: [0 0 0 0 0], len: 5, cap: 10 s1[0] = 100 // 可以直接使用 // 创建一个初始容量(可选)的 map m1 := make(map[string]int) m1[“age”] = 30 // 可以直接使用 fmt.Printf(“m1: %vn”, m1) // 创建一个带缓冲的 channel ch1 := make(chan int, 1) ch1 <- 1 // 可以直接使用 fmt.Printf(“Received from ch1: %dn”, <-ch1)
  • 特性 new(T) make(T, args…) 目的 分配内存,初始化为零值 创建并初始化 slice, map, channel 的内部结构 返回类型 指针 *T 类型 T 本身 (slice, map, or channel) 适用类型 任何类型 仅 slice, map, channel 初始化 内存被清零 (zero value) 初始化内部数据结构,使其立即可用 (non-nil) 常见用途 获取指向零值变量的指针,尤其是结构体指针 创建可用的 slice, map, channel
  • 这三种类型在 Go 中是引用类型,它们内部不仅仅是一块简单的内存区域,还包含了更复杂的数据结构: Slice: 内部包含指向底层数组的指针、长度(len)和容量(cap)。make 会分配底层数组并设置这些元数据。 Map: 内部通常是哈希表的实现。make 会初始化这个哈希表结构。 Channel: 内部包含用于 goroutine 间同步和通信的机制,可能还有缓冲区。make 会设置这些。 如果对这些类型使用 new: var s *[]int = new([]int) // *s 是一个 nil slice var m *map[string]int = new(map[string]int) // *m 是一个 nil map var c *chan int = new(chan int) // *c 是一个 nil channel 你会得到一个指向 nil slice/map/channel 的指针。这个 nil 状态的引用类型是不能直接使用的(例如,不能向 nil map 添加键值对,不能向 nil slice append 元素,不能向 nil channel 发送数据)。你需要先用 make 来初始化它们。
  • 使用 new(T): 当你需要一个指向某个类型 T 的变量,并且希望它被初始化为其零值时。 最常见的场景是为结构体分配内存并获取其指针,然后填充字段: type Point struct{ X, Y int } p := new(Point) // p 是 *Point,p.X 和 p.Y 都是 0 p.X = 10 这等价于: var p Point // p 是 Point,p.X 和 p.Y 都是 0 ptr := &p // ptr 是 *Point ptr.X = 10 或者更简洁的复合字面量: p := &Point{} // p 是 *Point,p.X 和 p.Y 都是 0 p.X = 10 使用 make(T, args…): 当你需要创建一个 slice、map 或 channel,并希望它们被正确初始化以便立即使用时。这是创建这三种类型的标准方式。 记住这个简单的规则: 要创建 slice, map, channel,请使用 make。 要为其他类型(如 int, string, struct, array)分配内存并获取指向其零值的指针,请使用 new(或者更常见的,使用复合字面量 &T{})。
  • 以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。 您可能感兴趣的文章: Go语言中make和new的区别及说明 一文告诉你大神是如何学习Go语言之make和new 详解Go语言中make和new的区别 Go语言中make和new函数的用法与区别 深入讲解Go语言中函数new与make的使用和区别
  • 目录
    • new
    • make
    • 核心区别总结
    • 为什么make只用于 slice, map, channel?
    • 何时使用哪个?
    • 总结

    在 Go 语言中,newmake 是两个用于内存分配的内置函数,但它们的作用和使用场景有显著区别。

    理解它们的核心在于:

    • new(T): 为类型 T 分配内存,并将其初始化为零值,然后返回一个指向该内存的指针 (*T)。
    • make(T, args...): 仅用于 slice、map 和 channel 这三种引用类型的创建和初始化。它返回的是类型 T 本身(而不是指针 *T),并且这个 T 已经被正确初始化,可以直接使用。

    下面详细解释:

    作用

    • 分配内存。
    • 将分配的内存清零(设置为相应类型的零值)。
    • 返回一个指向新分配的零值 T 的指针 (*T)。

    语法

    p := new(T)
    

    其中 T 可以是任何类型。

    返回值

    • 一个指向类型 T 的指针 (*T)。

    适用类型

    • 几乎所有类型,包括基本类型(int, string, bool等)、结构体(struct)、数组(array)等。
    • 也可以用于 slice, map, channel,但通常不这么用,因为 new 返回的是指向这些引用类型本身的指针,而引用类型本身在未初始化时是 nil

    示例

    // 为 int 分配内存,i 是 *int 类型,*i 的值是 0
    var i *int = new(int)
    fmt.Printf("i: %p, *i: %dn", i, *i) // *i 是 0
    
    // 为自定义结构体 MyStruct 分配内存,s 是 *MyStruct 类型
    type MyStruct struct {
        Field1 int
        Field2 string
    }
    var s *MyStruct = new(MyStruct)
    fmt.Printf("s: %p, s.Field1: %d, s.Field2: '%s'n", s, s.Field1, s.Field2) // s.Field1 是 0, s.Field2 是 ""
    
    // 对于引用类型(不推荐,但可以这么做)
    var sl *[]int = new([]int) // sl 是 *[]int 类型,*sl 的值是 nil
    fmt.Printf("sl: %p, *sl == nil: %tn", sl, *sl == nil) // *sl 是 nil,无法直接使用 append 等操作
    
    var m *map[string]int = new(map[string]int) // m 是 *map[string]int 类型,*m 的值是 nil
    fmt.Printf("m: %p, *m == nil: %tn", m, *m == nil) // *m 是 nil,无法直接赋值
    

    作用

    • 仅用于 slice、map 和 channel 这三种内置引用类型的创建。
    • 它不仅分配内存,还会初始化这些类型的内部数据结构,使其立即可用。

    语法

    • Slice: make([]T, length, capacity)make([]T, length) (capacity 默认为 length)
    • Map: make(map[K]V, initialCapacity)make(map[K]V) (initialCapacity 可选)
    • Channel: make(chan T, bufferCapacity)make(chan T) (bufferCapacity 可选,默认为0,即无缓冲)

    返回值

    • 返回的是初始化后的类型 T 本身(例如 []int, map[string]int, chan int),而不是指针。

    适用类型

    • 只能是 slice, map, channel。

    示例

    // 创建一个长度为 5,容量为 10 的 int 切片
    s1 := make([]int, 5, 10)
    fmt.Printf("s1: %v, len: %d, cap: %dn", s1, len(s1), cap(s1)) // s1: [0 0 0 0 0], len: 5, cap: 10
    s1[0] = 100 // 可以直接使用
    
    // 创建一个初始容量(可选)的 map
    m1 := make(map[string]int)
    m1["age"] = 30 // 可以直接使用
    fmt.Printf("m1: %vn", m1)
    
    // 创建一个带缓冲的 channel
    ch1 := make(chan int, 1)
    ch1 <- 1 // 可以直接使用
    fmt.Printf("Received from ch1: %dn", <-ch1)
    

    特性 new(T) make(T, args…)
    目的 分配内存,初始化为零值 创建并初始化 slice, map, channel 的内部结构
    返回类型 指针 *T 类型 T 本身 (slice, map, or channel)
    适用类型 任何类型 仅 slice, map, channel
    初始化 内存被清零 (zero value) 初始化内部数据结构,使其立即可用 (non-nil)
    常见用途 获取指向零值变量的指针,尤其是结构体指针 创建可用的 slice, map, channel

    这三种类型在 Go 中是引用类型,它们内部不仅仅是一块简单的内存区域,还包含了更复杂的数据结构:

    • Slice: 内部包含指向底层数组的指针、长度(len)和容量(cap)。make 会分配底层数组并设置这些元数据。
    • Map: 内部通常是哈希表的实现。make 会初始化这个哈希表结构。
    • Channel: 内部包含用于 goroutine 间同步和通信的机制,可能还有缓冲区。make 会设置这些。

    如果对这些类型使用 new

    var s *[]int = new([]int) // *s 是一个 nil slice
    var m *map[string]int = new(map[string]int) // *m 是一个 nil map
    var c *chan int = new(chan int) // *c 是一个 nil channel
    

    你会得到一个指向 nil slice/map/channel 的指针。这个 nil 状态的引用类型是不能直接使用的(例如,不能向 nil map 添加键值对,不能向 nil slice append 元素,不能向 nil channel 发送数据)。你需要先用 make 来初始化它们。

    使用 new(T)

    当你需要一个指向某个类型 T 的变量,并且希望它被初始化为其零值时。

    最常见的场景是为结构体分配内存并获取其指针,然后填充字段:

    type Point struct{ X, Y int }
    p := new(Point) // p 是 *Point,p.X 和 p.Y 都是 0
    p.X = 10
    

    这等价于:

    var p Point // p 是 Point,p.X 和 p.Y 都是 0
    ptr := &p   // ptr 是 *Point
    ptr.X = 10
    

    或者更简洁的复合字面量:

    p := &Point{} // p 是 *Point,p.X 和 p.Y 都是 0
    p.X = 10
    

    使用 make(T, args...)

    • 当你需要创建一个 slice、map 或 channel,并希望它们被正确初始化以便立即使用时。这是创建这三种类型的标准方式

    记住这个简单的规则:

    • 要创建 slice, map, channel,请使用 make
    • 要为其他类型(如 int, string, struct, array)分配内存并获取指向其零值的指针,请使用 new(或者更常见的,使用复合字面量 &T{})。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。

    您可能感兴趣的文章:

    • Go语言中make和new的区别及说明
    • 一文告诉你大神是如何学习Go语言之make和new
    • 详解Go语言中make和new的区别
    • Go语言中make和new函数的用法与区别
    • 深入讲解Go语言中函数new与make的使用和区别

    站内搜索