Go语言使用make进行内存分配的代码示例

 更新时间:2025年06月16日 09:14:25   作者:tekin  
在Go语言里,内存分配是程序开发中的关键环节,make是Go语言内置的一个重要函数,专门用于为切片(slice)、映射(map)和通道(channel)这三种引用类型分配内存并初始化,本文将深入剖析 make 函数的使用,结合代码示例与实际项目场景,帮助开发者更好地掌握这一特性

make 函数的基本概念

语法与适用类型

make 函数的语法格式为 make(T, args),其中 T 代表要创建的类型,必须是切片、映射或通道这三种引用类型之一,args 是根据不同类型而定的参数。以下是三种类型使用 make 函数的基本形式:

  • 切片make([]T, length, capacity),其中 T 是切片元素的类型,length 是切片的初始长度,capacity 是切片的初始容量(可省略,默认与长度相同)。
  • 映射make(map[K]V, initialCapacity)K 是键的类型,V 是值的类型,initialCapacity 是映射的初始容量(可省略)。
  • 通道make(chan T, bufferSize)T 是通道中元素的类型,bufferSize 是通道的缓冲区大小(可省略,省略时为无缓冲通道)。

代码示例

package main

import "fmt"

func main() {
    // 使用 make 创建切片
    slice := make([]int, 3, 5)
    fmt.Printf("切片长度: %d, 容量: %d, 内容: %v\n", len(slice), cap(slice), slice)

    // 使用 make 创建映射
    m := make(map[string]int)
    m["apple"] = 1
    m["banana"] = 2
    fmt.Println("映射内容:", m)

    // 使用 make 创建通道
    ch := make(chan int, 2)
    ch <- 10
    ch <- 20
    fmt.Println("从通道接收:", <-ch)
}

在上述代码中,分别使用 make 函数创建了切片、映射和通道,并进行了简单的操作。

切片的 make 分配

长度与容量的区别

在使用 make 创建切片时,长度和容量是两个重要的概念。长度表示切片中当前元素的数量,而容量表示切片底层数组的大小。可以通过 len() 函数获取切片的长度,通过 cap() 函数获取切片的容量。

package main

import "fmt"

func main() {
    // 创建一个长度为 2,容量为 5 的切片
    slice := make([]int, 2, 5)
    fmt.Printf("初始长度: %d, 初始容量: %d\n", len(slice), cap(slice))

    // 向切片追加元素
    slice = append(slice, 1, 2, 3)
    fmt.Printf("追加元素后长度: %d, 容量: %d, 内容: %v\n", len(slice), cap(slice), slice)
}

在这个示例中,初始创建的切片长度为 2,容量为 5。当使用 append 函数追加元素时,如果长度超过了容量,Go 语言会自动重新分配更大的底层数组。

项目场景:数据处理

在数据处理项目中,我们可能需要动态地处理一批数据。使用 make 创建切片可以预先分配一定的容量,减少内存重新分配的次数,提高性能。

package main

import (
    "fmt"
)

func processData() []int {
    // 预先分配容量为 100 的切片
    data := make([]int, 0, 100)
    for i := 0; i < 100; i++ {
        data = append(data, i)
    }
    return data
}

func main() {
    result := processData()
    fmt.Println("处理后的数据:", result)
}

映射的 make 分配

初始容量的作用

在使用 make 创建映射时,指定初始容量可以提高映射的性能。如果预先知道映射可能存储的元素数量,指定合适的初始容量可以减少哈希表扩容的次数。

package main

import "fmt"

func main() {
    // 创建一个初始容量为 10 的映射
    m := make(map[string]int, 10)
    for i := 0; i < 10; i++ {
        key := fmt.Sprintf("key%d", i)
        m[key] = i
    }
    fmt.Println("映射内容:", m)
}

项目场景:缓存系统

在缓存系统中,映射可以用于存储缓存数据。使用 make 创建映射并指定合适的初始容量,可以提高缓存系统的性能。

package main

import (
    "fmt"
)

type Cache struct {
    data map[string]interface{}
}

func NewCache(capacity int) *Cache {
    return &Cache{
        data: make(map[string]interface{}, capacity),
    }
}

func (c *Cache) Set(key string, value interface{}) {
    c.data[key] = value
}

func (c *Cache) Get(key string) (interface{}, bool) {
    val, exists := c.data[key]
    return val, exists
}

func main() {
    cache := NewCache(20)
    cache.Set("item1", 100)
    val, exists := cache.Get("item1")
    if exists {
        fmt.Println("缓存中获取的值:", val)
    }
}

通道的 make 分配

有缓冲通道与无缓冲通道

使用 make 创建通道时,可以指定缓冲区大小。如果不指定缓冲区大小,创建的是无缓冲通道,发送和接收操作会阻塞;如果指定了缓冲区大小,创建的是有缓冲通道,只有当缓冲区满时发送操作才会阻塞,只有当缓冲区为空时接收操作才会阻塞。

package main

import "fmt"

func main() {
    // 创建无缓冲通道
    ch1 := make(chan int)
    go func() {
        ch1 <- 10
        fmt.Println("数据已发送到无缓冲通道")
    }()
    fmt.Println("从无缓冲通道接收:", <-ch1)

    // 创建有缓冲通道
    ch2 := make(chan int, 2)
    ch2 <- 20
    ch2 <- 30
    fmt.Println("从有缓冲通道接收:", <-ch2)
}

项目场景:并发任务处理

在并发任务处理中,通道可以用于协程之间的通信。使用 make 创建合适的通道可以协调不同协程的工作。

package main

import (
    "fmt"
)

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Printf("Worker %d 开始处理任务 %d\n", id, j)
        results <- j * 2
    }
}

func main() {
    const numJobs = 5
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

    // 启动 3 个工作协程
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    // 发送任务
    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

    // 收集结果
    for a := 1; a <= numJobs; a++ {
        <-results
    }
    close(results)
}

总结

make 函数在 Go 语言中是为切片、映射和通道进行内存分配和初始化的重要工具。通过合理使用 make 函数,可以根据不同的需求为这些引用类型分配合适的内存,提高程序的性能和效率。在实际项目中,无论是数据处理、缓存系统还是并发任务处理,make 函数都发挥着关键作用。开发者需要深入理解 make 函数的使用方法和不同类型的特点,根据具体的场景灵活运用。

以上就是Go语言使用make进行内存分配的代码示例的详细内容,更多关于Go make内存分配的资料请关注脚本之家其它相关文章!

相关文章

  • go build -tags构建约束试验示例解析

    go build -tags构建约束试验示例解析

    这篇文章主要为大家介绍了go build -tags构建约束试验示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Golang配置管理Viper的实现

    Golang配置管理Viper的实现

    Viper是Go语言配置管理库,支持JSON/YAML/TOML等多格式,可动态监听配置变更,本文就来介绍一下Golang配置管理Viper的实现,感兴趣的可以了解一下
    2025-07-07
  • go语言vscode集成开发环境搭建

    go语言vscode集成开发环境搭建

    本文将介绍如何使用VSCode搭建Go语言开发环境,Go语言是一种简洁高效的编程语言,而VSCode是一款轻量级的集成开发环境,二者的结合可以提供良好的开发体验,
    2023-08-08
  • 快速解决Golang Map 并发读写安全的问题

    快速解决Golang Map 并发读写安全的问题

    这篇文章主要介绍了快速解决Golang Map 并发读写安全的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • go-zero创建RESTful API 服务的方法

    go-zero创建RESTful API 服务的方法

    文章介绍了如何使用go-zero框架和goctl工具快速创建RESTfulAPI服务,通过定义.api文件并使用goctl命令,可以自动生成项目结构、路由、请求和响应模型以及处理逻辑,感兴趣的朋友一起看看吧
    2024-11-11
  • go写文件后出现大量NUL字符问题解决

    go写文件后出现大量NUL字符问题解决

    本文主要介绍了go写文件后出现大量NUL字符问题解决,由于每次写的时候设置的长度都是64,在某次不足64时,byte切片空余位置被填充为空字符,下面就来介绍一下如何解决
    2023-12-12
  • Golang实现自己的Redis(有序集合跳表)实例探究

    Golang实现自己的Redis(有序集合跳表)实例探究

    这篇文章主要为大家介绍了Golang实现自己的Redis(有序集合跳表)实例探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Golang实现JWT身份验证的示例详解

    Golang实现JWT身份验证的示例详解

    JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用间安全地传输声明,本文主要为大家详细介绍了Golang实现JWT身份验证的相关方法,希望对大家有所帮助
    2024-03-03
  • GoLang socket网络编程传输数据包时进行长度校验的方法

    GoLang socket网络编程传输数据包时进行长度校验的方法

    在GoLang socket网络编程中,为了确保数据交互的稳定性和安全性,通常会通过传输数据的长度进行校验,发送端首先发送数据长度,然后发送数据本体,接收端则根据接收到的数据长度和数据本体进行比较,以此来确认数据是否传输成功
    2024-11-11
  • Windows+Linux系统下Go语言环境安装配置过程

    Windows+Linux系统下Go语言环境安装配置过程

    Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。这篇文章主要介绍了Windows+Linux系统下Go语言环境搭建配置过程,针对每种系统给大家讲解的非常详细,需要的朋友可以参考下
    2021-06-06

最新评论