跳转到主要内容
模块 4 · 第 2 课(共 5)课程中的17/50~15 min
模块课程(2/5)

切片:惯用结构

切片是 Go 中最常用的数据结构:动态视图 在底层数组上。语法:[]T。与数组不同的是,长度是 不是类型的一部分,您可以使用 append 来扩展它。

切片的解剖

切片内部是一个三字段结构:

  • 指向底层数组中第一个元素的指针
  • 长度 (len):可见元素的数量
  • 容量 (cap):从视图开始可用的元素 到底层数组的末尾
Go
s := []int{10, 20, 30}
fmt.Println(len(s), cap(s)) // 3 3

创建

Go
a := []int{1, 2, 3}          // literal
b := make([]int, 3)          // [0 0 0]   len=3 cap=3
c := make([]int, 3, 10)      // len=3 cap=10 (reserved)
var d []int                  // nil slice: len=0 cap=0, still usable with append

append:始终分配结果

append 添加元素并返回一个新切片(可能 如果容量不足则分配新数组):

Go
s := []int{1, 2, 3}
s = append(s, 4)              // [1 2 3 4]
s = append(s, 5, 6, 7)        // append multiple elements
s = append(s, altra...)       // concatenate another slice (spread)

切片表达式 s[a:b]

提取从 a (包含)到 b (不包含)的子切片:

Go
s := []int{10, 20, 30, 40, 50}
sub := s[1:4]              // [20 30 40]
inizio := s[:2]            // [10 20]
fine := s[3:]              // [40 50]
intera := s[:]             // [10 20 30 40 50]

子切片与原始切片共享底层数组: 通过 sub[i] = ... 的突变在 s 中也可见。

陷阱:数组共享

Go
s := []int{1, 2, 3, 4}
sub := s[0:2]
sub[0] = 99
fmt.Println(s)             // [99 2 3 4] — modified!

要获取独立副本,请使用 copy 或 append:

Go
out := make([]int, len(sub))
copy(out, sub)

尝试一下

锻炼#go.m4.l2.e1
尝试:0加载中...

使用 [1, 2, 3] 创建一个切片 s 并使用append 添加 4。

正在加载编辑器...
显示提示

始终将追加的结果分配回“s”。

3 次尝试后可用的解决方案

锻炼#go.m4.l2.e2
尝试:0加载中...

使用切片表达式从索引 1(含)到 3(不含)提取元素(即 [20, 30])。

正在加载编辑器...
显示提示

语法:`s[start:end]`,包含`start`,不包含`end`。

3 次尝试后可用的解决方案

Quiz#go.m4.l2.e3
准备好

以下哪个写法是错误的?

Go
s := []int{1, 2, 3}
// (a) s = append(s, 4)
// (b) append(s, 4)
答案选项

回顾

  • []T:数组的动态视图;三重(ptr、len、cap)。
  • make([]T, len, cap) 进行预分配; var s []T 用于可用的 nil 切片。
  • s = append(s, ...):始终分配结果。
  • s[a:b] 共享底层数组:copy(...) 用于独立副本。
  • nil 切片 = 可以读取/范围/追加;与 nil 地图完全不同。