Go 切片 Slice 与 range

切片是长度可变的"动态数组",比数组常用得多。它不直接存数据,而是底层数组某段的视图,内部结构是指针 + 长度 len + 容量 cap。(说明:文中的片段代码需放进完整程序里运行)

创建切片:make、字面量、len 与 cap

完整示例:

package main

import "fmt"

func main() {
	s1 := []int{1, 2, 3}    // 字面量
	s2 := make([]int, 3)    // 长度 3,元素默认 0
	s3 := make([]int, 3, 5) // 长度 3,容量 5
	var s4 []int            // 零值切片 == nil
	fmt.Println(s1, len(s1), cap(s1))
	fmt.Println(s2, len(s2), cap(s2))
	fmt.Println(s3, len(s3), cap(s3))
	fmt.Println(s4 == nil)
}
// 输出:
// [1 2 3] 3 3
// [0 0 0] 3 3
// [0 0 0] 3 5
// true

make([]类型, 长度, 容量) 中容量可省略,省略时等于长度。len 是现有元素个数,cap 是从起点到底层数组末尾最多还能装多少。

取片段:共享底层数组

x[a:b] 左闭右开地对数组/切片取片段,得到的新切片与原来共享底层数组

arr := [5]int{10, 20, 30, 40, 50}
s := arr[1:4]                  // 下标 1、2、3
fmt.Println(s, len(s), cap(s)) // [20 30 40] 3 4

s2 := s[:cap(s)] // 可扩到容量上限,多出元素 50
s2[0] = 99       // 改动会反映到 arr
fmt.Println(arr) // [10 99 30 40 50]

append 与 copy

append 追加元素,容量不够时自动扩容并换底层数组,所以必须写成 s = append(s, ...)

s := []int{1, 2}
s = append(s, 3, 4)
fmt.Println(s) // [1 2 3 4]

dst := make([]int, len(s))
copy(dst, s) // 真正复制元素,得到独立切片
dst[0] = 100
fmt.Println(s, dst) // [1 2 3 4] [100 2 3 4]

range 遍历数组、切片、map、字符串

range 是万能遍历语法:遍历数组/切片得到下标和值,遍历 map 得到键和值,遍历字符串时下标是字节位置、值是 rune:

s := []string{"春", "夏", "秋", "冬"}
for i, v := range s { // 不需要下标时写 for _, v := range s
	fmt.Printf("%d:%s ", i, v)
}
// 春 夏 秋 冬

m := map[string]int{"语文": 90, "数学": 85}
for k, v := range m { // map 遍历顺序随机
	fmt.Printf("%s=%d ", k, v)
}
for i, c := range "你好" { // 每个汉字占 3 字节
	fmt.Printf("%d:%c ", i, c) // 0:你 3:好
}

小结:切片是"数组的视图 + len/cap 两把尺子";append 会扩容,copy 做深拷贝,range 一键遍历。

笔记加载中…