Golang — make 关键字

make 关键字

This article is extracted from the chat log with AI. Please identify it with caution.

在Go语言中,make是用于初始化内置引用类型(slice、map、channel)的内置函数。以下是不同场景下的详细使用案例:


1. 切片(Slice)初始化#

基础用法 #

// 创建长度为3,容量为5的整型切片
s := make([]int, 3, 5)  // s = [0 0 0], len=3, cap=5

// 创建长度和容量都为10的字符串切片
names := make([]string, 10)  // 10个空字符串

性能优化(预分配) #

// 预分配大容量避免append时的频繁扩容
data := make([]byte, 0, 1024 * 1024)  // 预分配1MB空切片
for i := 0; i < 100000; i++ {
    data = append(data, byte(i%256))  // 无扩容开销
}

二维切片 #

// 创建5x3的二维整型切片
matrix := make([][]int, 5)  // 先创建外层
for i := range matrix {
    matrix[i] = make([]int, 3)  // 每行初始化
}
// 结果: [[0,0,0], [0,0,0], ...]

2. 映射(Map)初始化#

基础用法 #

// 创建字符串到整型的空映射
scores := make(map[string]int)

// 带初始容量的映射(减少扩容)
config := make(map[string]string, 20)  // 预分配20个键的空间

复杂值类型 #

// 值为切片的映射
studentCourses := make(map[string][]string)
studentCourses["Alice"] = []string{"Math", "Physics"}

// 值为映射的映射
graph := make(map[int]map[int]bool)  // 邻接表
graph[1] = make(map[int]bool)
graph[1][2] = true  // 节点1指向节点2

3. 通道(Channel)初始化#

无缓冲通道(同步) #

// 创建整型无缓冲通道
ch := make(chan int)

go func() {
    ch <- 42  // 发送阻塞直到接收
}()

value := <-ch  // 接收并解除发送阻塞

带缓冲通道(异步) #

// 创建缓冲大小为100的任务通道
taskQueue := make(chan Task, 100)

// 生产者
go func() {
    for i := 0; i < 1000; i++ {
        taskQueue <- NewTask(i)  // 缓冲区满时阻塞
    }
}()

// 消费者
go func() {
    for task := range taskQueue {
        process(task)
    }
}()

信号通道 #

// 创建空结构体通道用于信号传递
exitSignal := make(chan struct{})

go func() {
    time.Sleep(5 * time.Second)
    close(exitSignal)  // 关闭通道广播信号
}()

<-exitSignal  // 阻塞直到通道关闭

4. 特殊场景案例#

复用内存池 #

// 创建字节切片池减少GC压力
var bufPool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 1024)  // 创建1KB切片
    }
}

func getBuffer() []byte {
    return bufPool.Get().([]byte)
}

func putBuffer(buf []byte) {
    bufPool.Put(buf[:0])  // 重置后放回
}

高性能解析 #

// 复用缓冲区解析JSON
func ParseJSON(data []byte, v interface{}) error {
    buf := make([]byte, len(data))
    copy(buf, data)  // 避免修改原始数据
    return json.Unmarshal(buf, v)
}

并发安全Map #

// 使用sync.Map的场景(通常不需要make)
// 但需要初始化内部结构:
var safeMap sync.Map
safeMap.Store("key", make([]int, 0))  // 初始化值

关键注意事项#

  1. make vs new​:

    // new 返回指针 *[]int
    p := new([]int)    // *p == nil
    
    // make 返回初始化后的引用
    s := make([]int, 0) // 可直接使用的切片
    
  2. 零值vs make​:

    var m map[string]int  // nil映射(写入会panic!)
    validMap := make(map[string]int)  // 可安全写入
    
  3. 容量提示​:

    // 对map和slice只是提示而非强制约束
    m := make(map[int]int, 1000)  // 预分配哈希桶
    s := make([]int, 0, 1e6)      // 预分配内存
    
  4. 通道方向​:

    // 创建只发送通道
    var sendOnly chan<- int = make(chan int)
    
    // 创建只接收通道
    var recvOnly <-chan int = make(chan int)
    

性能最佳实践#

// 错误:频繁创建小切片
for i := 0; i < 10000; i++ {
    data := make([]byte, 10)  // 每次循环都分配
    // ...
}

// 正确:复用切片
buf := make([]byte, 10)       // 单次分配
for i := 0; i < 10000; i++ {
    buf = buf[:0]             // 重置复用
    // 使用buf...
}

通过合理使用make,可以优化内存分配、减少GC压力,并构建高效安全的数据结构。

本文共 1066 字,创建于 Aug 9, 2025
相关标签: Golang, ByAI