Go语言数组与切片的区别

数组与切片的区别

一句话结论:

数组是“值类型容器”
切片是“指向数组的引用视图”

再直白一点:

  • 数组:我自己就是数据
  • 切片:我只是看数据的一扇窗

  • 数组 = 盒子
  • 切片 = 指向盒子的标签
  • 复制盒子 → 内容独立
  • 复制标签 → 看同一个盒子

一、最本质的 4 个区别(核心)

对比点

数组(array)

切片(slice)

类型

值类型

引用语义(结构体)

长度

固定,类型的一部分

可变

内存

自己持有数据

指向底层数组

常用性

很少直接用

Go 的主力

二、类型层面的区别(非常关键)

数组:长度是类型的一部分

var a [3]int
var b [4]int

👉 a 和 b 是完全不同的类型

a = b // ❌ 编译错误

切片:长度不是类型的一部分

var s1 []int
var s2 []int

👉 无论多长,类型都一样

三、内存模型区别(理解一切 bug 的根源)

数组(独立内存)

a := [3]int{1, 2, 3}
b := a
b[0] = 100

结果:

a = [1 2 3]
b = [100 2 3]

👉 值拷贝

切片(共享底层数组)

a := []int{1, 2, 3}
b := a
b[0] = 100

结果:

a = [100 2 3]
b = [100 2 3]

👉 共享底层数组

四、作为函数参数的区别

数组传参:完整拷贝(非常重)

func f(a [3]int) {
    a[0] = 100
}

func main() {
    x := [3]int{1, 2, 3}
    f(x)
    fmt.Println(x)
}

输出:

[1 2 3]

切片传参:拷贝 slice 头(轻)

func f(s []int) {
    s[0] = 100
}

func main() {
    x := []int{1, 2, 3}
    f(x)
    fmt.Println(x)
}

输出:

[100 2 3]

五、长度与容量(数组没有 cap)

a := [3]int{1, 2, 3}

len(a) // 3
cap(a) // ❌ 不存在

s := []int{1, 2, 3}

len(s) // 3
cap(s) // >= 3

👉 cap 是 slice 独有的概念

六、创建方式差异

数组(少见)

a := [3]int{1, 2, 3}
a := [...]int{1, 2, 3} // 编译期推断

切片(主流)

s := []int{1, 2, 3}
s := make([]int, 3)
s := make([]int, 0, 10)

七、为什么 Go 设计数组 + 切片两套?

一句话:

数组用于“确定大小的数据结构”
切片用于“动态、高效的数据处理”

数组适合:

  • 小型、固定大小
  • 值语义(拷贝安全)
  • 底层数据结构(如哈希桶)

切片适合:

  • 几乎所有业务代码
  • 传参
  • 集合、列表、缓冲区

八、工程级使用建议

✅ 99% 场景用切片

func process(data []byte)

✅ 用数组的 3 种典型场景

1️⃣ 编译期固定大小

var buf [32]byte // hash / uuid

2️⃣ 明确要值语义

type Point struct {
    XY [2]int
}

3️⃣ 性能 / 底层库

var table [256]byte
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小信啊啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值