Golang笔记—— new() 、 make() 和简短声明符

大家好,这里是编程Cookbook,关注公众号「编程Cookbook」,获取更多面试资料。详细介绍Golang的new() 、 make() 和简短声明符的区别和使用。



在 Go 语言中,new()make() 都是用来分配内存的内建函数,但是有很大区别。

new() 函数

关注公众号「编程Cookbook」,获取更多编程学习/面试资料!

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
  • Type:可以是任何类型(包括基础类型、结构体、数组等)。

返回值:

  • new() 返回一个指向类型的指针。该类型的值会被初始化为其零值(例如,整数为 0,布尔值为 false,指针为 nil,字符串为空字符串等)。

示例:

package main

import "fmt"

func main() {
    // 使用 new 创建一个 int 类型的指针
    p := new(int)

    // new 返回的是指向 int 的指针,指针的初始值是零值,即 0
    fmt.Println(*p)  // 输出: 0
    
    *p = 42  // 修改 p 指向的值
    fmt.Println(*p)  // 输出: 42
}

make() 函数

关注公众号「编程Cookbook」,获取更多编程学习/面试资料!

make() 函数用于 初始化切片(slice)、映射(map)和通道(channel),并返回一个已经初始化的(且可以使用的)对象

  • 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. The specification of the result depends on
// the type:
//
//	Slice: The size specifies the length. The capacity of the slice is
//	equal to its length. A second integer argument may be provided to
//	specify a different capacity; it must be no smaller than the
//	length. For example, make([]int, 0, 10) allocates an underlying array
//	of size 10 and returns a slice of length 0 and capacity 10 that is
//	backed by this underlying array.
//	Map: An empty map is allocated with enough space to hold the
//	specified number of elements. The size may be omitted, in which case
//	a small starting size is allocated.
//	Channel: The channel's buffer is initialized with the specified
//	buffer capacity. If zero, or the size is omitted, the channel is
//	unbuffered.
func make(t Type, size ...IntegerType) Type
  • Type:要创建的类型,可以是 slicemapchannel
  • size
    • 对于 channelmake 只允许 1 个参数,表示通道的缓冲区容量。
    • 对于 mapmake 只允许 1 个参数,表示映射的初始容量。
    • 对于 slicemake 允许 2 个参数,分别表示切片的长度和容量。
对于不同类型的说明
  1. 切片(Slice)

    • 长度size 参数指定切片的长度,必传
    • 容量:可选参数,切片的容量等于它的长度。如果指定了第二个参数 capacity,则表示切片的容量。capacity 必须大于或等于 size

    为了避免意外修改原切片数据,建议通过添加切片的第三个索引限制容量,从而在扩容时强制触发新底层数组的创建。

  2. 映射(Map)

    • size参数可选。
    • make 为映射分配内存,并根据指定的 元素数量 初始化映射。可以提供一个整数参数来指定映射的初始容量
    • 如果没有指定容量,Go 会为映射分配一个小的默认容量。
  3. 通道(Channel)

    • size参数可选。
    • make 用于创建一个 带缓冲区的通道size 参数指定通道的 缓冲区容量
    • 如果没有指定 size 或指定为 0,则创建一个 无缓冲通道,即通道会阻塞直到接收方接收数据。

同时,在使用 len()cap() 时候注意:

  • 切片(slice)len 返回元素的数量,cap 返回底层数组的容量。
  • 映射(map)len 返回键值对的数量,但没有 cap 函数
  • 通道(channel)len 返回通道中的元素数量,cap 返回通道的缓冲区容量。

返回值:

  • make() 返回的是已经初始化的对象(切片、映射或通道本身),并且可以直接使用。

示例:

package main

import "fmt"

func main() {
    // 创建一个长度为 5 的整数切片
    slice := make([]int, 5)
    fmt.Println(slice)  // 输出: [0 0 0 0 0]
    
    // 创建一个长度为 3,容量为 5 的切片
    slice2 := make([]int, 3, 5)
    fmt.Println(slice2)  // 输出: [0 0 0]
    
    // 创建一个容量为 10 的整数通道
    ch := make(chan int, 10)
    ch <- 42  // 向通道中发送数据
    fmt.Println(<-ch)  // 输出: 42

    // 创建一个具有初始大小的映射
    m := make(map[string]int)
    m["key"] = 10
    fmt.Println(m)  // 输出: map[key:10]
}

简短声明 :=

关注公众号「编程Cookbook」,获取更多编程学习/面试资料!

  • 使用 Go 中的简短声明符 := 时,可以同时声明和初始化这些类型。不需要手动声明变量类型,Go 会自动推导出变量的类型,并给它赋予一个初始值。
  • := 可以与 make() 和 new() 结合使用,简化变量声明和初始化过程,上面make()new()的示例中已有展示结合使用,当然也可以不与make()new()结合使用。如下,直接进行变量声明。

示例

package main

import "fmt"

func main() {
    // 使用 := 创建并初始化一个 map
    m := map[string]int{
        "apple":  5,
        "banana": 3,
        "orange": 2,
    }

    // 输出 map 中的元素
    fmt.Println(m) // 输出: map[apple:5 banana:3 orange:2]
}

这里,p := 0 创建了一个类型为 int 的变量 p,并将其初始化为 0,而不是指向 0 的指针。p 本身是一个值,而不是一个指针

new()make():= 的比较

特性new()make():=
用法用于任何类型(包括基础类型、结构体、数组等)仅用于 slicemapchannel 类型用于声明变量并初始化为零值或指定值
返回值返回类型的指针,指向零值返回初始化后的对象,已经可以使用返回值,而非指针
初始化内容只会分配内存并初始化为零值根据类型进行初始化(例如,初始化切片的长度和容量,初始化映射的哈希表)直接创建变量并赋初值(默认为零值)
支持类型所有类型slicemapchannel所有类型(包括切片、映射、通道、基础类型)
返回类型类型的指针(例如 *int*struct 等)对象本身(例如切片、映射、通道)变量本身(值类型或引用类型)
内存分配分配零值内存并返回指针分配并初始化内存,返回已初始化的对象分配并初始化变量
适用场景创建指向零值的指针,通常用于结构体或基本类型用于切片、映射、通道的内存分配和初始化用于直接创建并初始化变量,不涉及指针

总结

关注公众号「编程Cookbook」,获取更多编程学习/面试资料!

  • new():用于为任意类型分配内存并返回该类型的指针,默认值为零值
  • make():用于初始化切片、映射和通道并返回已初始化的对象。它不仅分配内存,还为这些类型做了额外的初始化工作。
  • :=:可以结合 new()make() 使用,简化变量声明和初始化过程。

注意事项

  1. new()make() 的区别
    • new() 返回指针,make() 返回对象。
    • new() 适用于任意类型,make() 仅适用于 slicemapchannel
  2. := 的使用场景
    • 只能在函数内部使用,不能在全局作用域使用。
    • 不能用于已声明的变量(除非重新赋值)。

补充

关注公众号「编程Cookbook」,获取更多编程学习/面试资料!

上面主要讲的是 new() 、 make() 函数的区别,也讲了一点简短声明符 := (这算Go所特有的)。当然,也可以不使用new() 、 make() 和 := ,而是使用var先声明,再进行初始化(slice,map,channle必须初始化,不能直接赋值,声明后未初始化会导致 panic)。

  • 使用 var 声明时,slicemapchannel 的零值是 nil,它们必须经过初始化才能使用。
  • 初始化方法
    • 使用 make():最常见的初始化方式,适用于 slicemapchannel
    • 使用字面量语法(s := []int{1, 2, 3} // 切片字面量):对于 slicemap,可以使用字面量语法进行初始化。
  • 未初始化的 nil 类型不能直接使用,否则会导致 panic
普通变量声明并后续初始化
package main

import "fmt"

func main() {
    var x int    // 声明一个变量 x,类型是 int,零值是 0
    fmt.Println(x)  // 输出 0

    // 后续赋值
    x = 10
    fmt.Println(x)  // 输出 10
}
初始化切片
package main

import "fmt"

func main() {
    var s []int  // 声明一个切片,零值是 nil
    fmt.Println(s)  // 输出: []

    // 后续使用 append 或其他方式进行初始化
    s = append(s, 1, 2, 3)
    fmt.Println(s)  // 输出: [1 2 3]
}
初始化映射
package main

import "fmt"

func main() {
    var m map[string]int  // 声明一个映射,零值是 nil
    fmt.Println(m)  // 输出: map[]

    // 后续初始化映射
    m = make(map[string]int)
    m["apple"] = 5
    m["banana"] = 3
    fmt.Println(m)  // 输出: map[apple:5 banana:3]
}
初始化通道
package main

import "fmt"

func main() {
    var ch chan int  // 声明一个通道,零值是 nil
    fmt.Println(ch)  // 输出: <nil>

    // 后续初始化通道
    ch = make(chan int, 3)
    ch <- 1
    fmt.Println(<-ch)  // 输出: 1
}

关注公众号「编程Cookbook」,获取更多编程学习/面试资料!

历史文章

MySQL数据库

MySQL数据库

Redis

Redis数据库笔记合集

Golang

  1. Golang笔记——语言基础知识
  2. Golang笔记——切片与数组
  3. Golang笔记——hashmap
  4. Golang笔记——rune和byte
  5. Golang笔记——channel
  6. Golang笔记——Interface类型
  7. Golang笔记——数组、Slice、Map、Channel的并发安全性
  8. Golang笔记——协程同步
  9. Golang笔记——并发控制
  10. Golang笔记——GPM调度器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值