首页 > 后端开发 > Golang > 正文

Go语言中切片指针的预分配与填充:惯用方法解析

DDD
发布: 2025-10-13 12:43:14
原创
190人浏览过

Go语言中切片指针的预分配与填充:惯用方法解析

本文深入探讨了在go语言中如何以惯用的方式预分配和填充包含指针的切片。通过分析`make`函数对切片长度和容量的影响,以及`append`操作的行为,文章指出了常见的误区。我们提供了两种主要的解决方案:一是通过直接索引来填充已预设长度的切片,二是利用`make`函数预设容量并结合`append`操作来高效构建切片。

在Go语言中,切片(slice)是构建动态数组的强大工具。然而,当涉及到预分配并填充包含指针的切片时,如果不理解make函数和append操作的底层机制,可能会导致非预期的结果。本文将详细阐述Go语言中预分配和填充切片的惯用方法。

理解make与append的行为

在Go中,make函数用于创建切片、映射或通道。对于切片,它有以下两种常用形式:

  1. make([]Type, length): 创建一个长度为length的切片,其所有元素都会被初始化为Type的零值。对于指针类型*Type,零值是nil。切片的容量(capacity)默认与长度相等。
  2. make([]Type, length, capacity): 创建一个长度为length,容量为capacity的切片。同样,所有元素会被初始化为Type的零值。

append函数用于向切片追加元素。它总是将新元素添加到切片的末尾,并返回一个新的切片(如果底层数组需要重新分配)。append操作会增加切片的长度,但不会改变已存在元素的索引或值。

常见误区示例

考虑以下代码,尝试预分配一个包含5个*UselessStruct指针的切片,然后使用append填充:

立即学习go语言免费学习笔记(深入)”;

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    mySlice := make([]*UselessStruct, 5) // 长度为5,元素为5个nil指针
    for i := 0; i != 5; i++ {
        mySlice = append(mySlice, &UselessStruct{}) // 追加新元素
    }

    fmt.Println(mySlice)
}
登录后复制

这段代码的输出是:[<nil> <nil> <nil> <nil> <nil> 0xc0... 0xc0... 0xc0... 0xc0... 0xc0...]。 可以看到,前5个元素仍然是nil,append操作并没有替换这些nil值,而是将新的UselessStruct指针追加到了切片的末尾,导致切片的长度变成了10。

如果切片存储的是结构体值而非指针,情况类似:

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    mySlice := make([]UselessStruct, 5) // 长度为5,元素为5个零值UselessStruct
    for i := 0; i != 5; i++ {
        mySlice = append(mySlice, UselessStruct{}) // 追加新元素
    }

    fmt.Println(mySlice)
}
登录后复制

输出将是:[{0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0}]。 同样,前5个元素是零值结构体,后续追加的才是新的结构体。

这表明,当使用make([]Type, length)创建一个具有非零长度的切片时,切片已经包含了length个元素(零值)。append操作只会在此基础上增加新元素,而不会覆盖已存在的元素。

惯用解决方案

Go语言提供了两种惯用的方法来正确地预分配和填充切片,具体取决于你的需求:

法语写作助手
法语写作助手

法语助手旗下的AI智能写作平台,支持语法、拼写自动纠错,一键改写、润色你的法语作文。

法语写作助手 31
查看详情 法语写作助手

方案一:直接索引填充(适用于已知固定长度)

当你事先知道切片的最终长度,并且希望填充所有元素时,最直接和惯用的方法是使用make([]Type, length)创建切片,然后通过索引直接为每个位置赋值。

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    const size = 5
    mySlice := make([]*UselessStruct, size) // 创建一个长度为5的切片,元素为nil指针

    // 通过索引直接填充每个位置
    for i := range mySlice {
        mySlice[i] = new(UselessStruct) // 为每个位置分配并赋值一个新的UselessStruct指针
        // 或者使用 &UselessStruct{} 也可以
        // mySlice[i] = &UselessStruct{}
    }

    fmt.Println(mySlice)
    // 预期输出:[0xc0... 0xc0... 0xc0... 0xc0... 0xc0...] (5个不同的指针)
}
登录后复制

在这个例子中:

  • make([]*UselessStruct, size)创建了一个长度为size的切片,其中包含size个nil指针。
  • for i := range mySlice遍历切片的索引。
  • mySlice[i] = new(UselessStruct)在每个索引位置上创建了一个新的UselessStruct实例,并将其地址赋值给mySlice[i]。new(UselessStruct)和&UselessStruct{}都用于创建结构体实例的指针,它们在大多数情况下是等效的。

这种方法简洁明了,直接表达了“我需要一个固定大小的切片,并用特定值填充它”的意图。

方案二:预设容量与append结合(适用于动态增长但需优化性能)

当你需要动态地向切片添加元素,但又希望通过预分配内存来避免频繁的底层数组重新分配(这会带来性能开销)时,可以使用make([]Type, 0, capacity)来创建切片。这会创建一个长度为0但预留了capacity空间(底层数组)的切片。

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    const capacity = 5
    // 创建一个长度为0,但容量为5的切片
    mySlice := make([]*UselessStruct, 0, capacity)

    // 使用append追加元素
    for i := 0; i < capacity; i++ {
        mySlice = append(mySlice, &UselessStruct{}) // 追加新的UselessStruct指针
    }

    fmt.Println(mySlice)
    // 预期输出:[0xc0... 0xc0... 0xc0... 0xc0... 0xc0...] (5个不同的指针)
}
登录后复制

在这个例子中:

  • make([]*UselessStruct, 0, capacity)创建了一个空切片,但底层数组已分配了容纳capacity个元素的空间。
  • append操作会将新元素添加到切片的末尾。由于切片有足够的容量,前capacity次append操作不会导致底层数组的重新分配,从而提高了效率。
  • 每次append都会增加切片的长度。

这种方法适用于你不知道最终长度,但可以预估一个大致容量的场景,以优化性能。

总结与注意事项

  • make([]Type, length):创建一个包含length个零值元素的切片。如果你想填充所有这些元素,应该使用索引mySlice[i] = value来赋值。
  • make([]Type, 0, capacity):创建一个空切片,但预留了capacity的内存空间。如果你打算通过append动态添加元素,并希望优化性能,这是首选方式。
  • append操作:append总是将元素添加到切片的末尾,并增加切片的长度。它不会覆盖或替换切片中已存在的元素。
  • 指针类型与值类型:无论是切片指针还是切片值,上述原则都适用。对于指针切片,你通常会分配新的对象并获取其地址(如new(Type)或&Type{});对于值切片,你直接提供值即可。

理解这些基本概念是编写高效、惯用Go代码的关键。选择哪种方法取决于你的具体需求:如果长度固定且已知,直接索引填充更简洁;如果长度动态且需要性能优化,预设容量并结合append是更好的选择。

以上就是Go语言中切片指针的预分配与填充:惯用方法解析的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号