Golang 数组、切片的实际应用

在Go语言中,数组和切片是两种核心的数据结构。它们在实际开发中有不同的应用场景和优势。本篇文章带你详细了解。

1. 数组(Array)

特点

  • 固定长度(长度是类型的一部分,如 [5]int[10]int 是不同类型)
  • 值类型(赋值或传参时会复制整个数组)
  • 内存连续分配,访问高效

实际应用场景

(1) 存储固定大小的数据集合

go 复制代码
// 存储一周的每日温度
var weeklyTemps [7]float64
weeklyTemps = [7]float64{18.5, 20.1, 22.3, 21.7, 19.4, 17.8, 16.2}

(2) 内存敏感场景(避免堆分配)

数组在栈上分配,适合小规模固定数据:

go 复制代码
// 存储RGBA像素值(固定4字节)
type Pixel [4]byte // R, G, B, A
pixel := Pixel{255, 0, 0, 255} // 红色

(3) 加密/编码等底层操作

需精确控制内存布局时:

go 复制代码
// MD5哈希值存储(固定16字节)
var hash [16]byte
copy(hash[:], md5.Sum(data))

2. 切片(Slice)

特点

  • 动态长度(底层引用数组,可动态扩容)
  • 引用类型(传递时仅复制切片头,不复制底层数据)
  • 内置操作(append, 切片表达式 s[i:j]

实际应用场景

(1) 动态数据集合(最常见用法)

go 复制代码
// 读取文件内容(长度未知)
data, _ := os.ReadFile("file.txt") // data 是 []byte 切片
lines := strings.Split(string(data), "\n")

// 动态添加用户
users := []string{"Alice", "Bob"}
users = append(users, "Charlie") // 自动扩容

(2) 复用内存(避免复制)

go 复制代码
// 截取子集(共享底层数组)
log := []byte("2023-10-01 ERROR: Disk full")
errorMsg := log[11:] // "ERROR: Disk full"(无数据复制)

(3) 实现栈/队列

go 复制代码
// 栈操作
stack := []int{}
stack = append(stack, 1)      // 压栈
top := stack[len(stack)-1]     // 取栈顶
stack = stack[:len(stack)-1]  // 弹栈

// 队列(需谨慎,出队可能导致底层数组移位)
queue := []int{1,2,3}
queue = queue[1:] // 出队(2,3)

(4) 高性能批量处理

go 复制代码
// 分批处理任务(复用内存)
batchSize := 100
data := make([]int, 0, 10000) // 预分配容量
for i := 0; i < 10000; i++ {
    data = append(data, i)
    if len(data) == batchSize {
        processBatch(data) // 处理批次
        data = data[:0]   // 重置切片(底层数组保留)
    }
}

(5) 避免内存泄漏

go 复制代码
func ReadBigFile() []byte {
    data := make([]byte, 0, 10*1024*1024) // 预分配10MB
    // ...填充数据...
    return data[:len(data)] // 返回实际大小的切片
}

特性 数组 (Array) 切片 (Slice)
长度 固定(编译时确定) 动态(运行时可扩展)
内存分配 值类型(复制整个数据) 引用类型(复制切片头)
传递开销 大(适合小数组) 小(适合大型数据)
适用场景 固定大小、内存敏感、栈分配 动态数据、共享内存、高频操作

3. 最佳实践

  1. 优先用切片:95%的场景使用切片(动态性更灵活)。

  2. 预分配容量

    go 复制代码
    // 已知最大规模时预分配
    s := make([]int, 0, 1000) // 长度0,容量1000
  3. 避免意外修改

    go 复制代码
    // 返回切片的拷贝(防止外部修改底层数组)
    func SafeReturn() []int {
        data := []int{1, 2, 3}
        return append([]int{}, data...) // 复制数据
    }
  4. 数组转切片

    go 复制代码
    arr := [3]int{1,2,3}
    slice := arr[:] // 转为切片(共享内存)

4. 性能陷阱

应用时不够谨慎可能会带来一些麻烦:

  • 切片扩容append 可能触发复制(容量不足时)。

  • 大数组传参:值复制代价高,应改用切片或指针。

  • 内存泄漏 :大切片的小子切片会阻止整个底层数组被GC回收:

    go 复制代码
    bigData := make([]byte, 100*1024*1024) // 100MB
    smallPart := bigData[:10] // 保留整个100MB内存!
    // 解决方案:复制需要的数据
    smallPart := make([]byte, 10)
    copy(smallPart, bigData)

以上就是二者对比。

总结

  • 数组:固定大小数据、栈分配敏感、精确内存控制(如加密/硬件交互)。
  • 切片:动态数据集合、高效内存复用、数据分块处理(90%+场景)。
相关推荐
光头闪亮亮16 小时前
电子发票解析工具-golang服务端开发案例详解
go
Mgx20 小时前
从“CPU 烧开水“到优雅暂停:Go 里 sync.Cond 的正确打开方式
go
GM_8281 天前
从0开始在Go当中使用Apache Thrift框架(万字讲解+图文教程+详细代码)
rpc·go·apache·thrift
Kratos开源社区2 天前
别卷 LangChain 了!Blades AI 框架让 Go 开发者轻松打造智能体
go·agent·ai编程
Kratos开源社区2 天前
跟 Blades 学 Agent 设计 - 01 用“提示词链”让你的 AI 助手变身超级特工
llm·go·agent
百锦再2 天前
第10章 错误处理
java·git·ai·rust·go·错误·pathon
Mgx3 天前
从 4.8 秒到 0.25 秒:我是如何把 Go 正则匹配提速 19 倍的?
go
遥天棋子4 天前
实战PaddleOCR自动识别车位坐标并渲染可点击按钮
go
久违 °4 天前
【安全开发】Nuclei源码分析-任务执行流程(三)
安全·网络安全·go
喵个咪4 天前
开箱即用的GO后台管理系统 Kratos Admin - 数据脱敏和隐私保护
后端·go·protobuf