数组、切片与 Map
约 1091 字大约 4 分钟
2025-04-17
数组
数组是固定长度的同类型元素序列,长度不可变。
数组定义
// 方法1:var 声明,零值初始化
var arr1 [5]int // [0, 0, 0, 0, 0]
// 方法2:字面量初始化
arr2 := [3]int{1, 2, 3}
arr3 := [...]int{1, 2, 3} // 编译器推导为 [3]int
// 方法3:指定索引初始化
arr4 := [5]int{1: 10, 3: 30} // [0, 10, 0, 30, 0]重要
数组定义时必须指定长度,定义后可以修改元素值,但长度不可变。
var person = [3]string{"som", "tom", "john"}
person[2] = "poter" // 修改元素值 ✅
// person[3] = "amy" // 编译错误 ❌ 数组越界切片(Slice)
切片是数组的动态长度视图,长度可变,是 Go 中最常用的集合类型。
切片定义
// 方法1:var 声明(nil 切片)
var slice1 []int // nil,长度和容量为 0
// 方法2:字面量初始化
slice2 := []int{1, 2, 3} // 长度 = 容量 = 3
// 方法3:make 创建
slice3 := make([]int, 5) // 长度 = 容量 = 5
slice4 := make([]int, 3, 5) // 长度 = 3,容量 = 5
// 方法4:从数组或切片切割
arr := [5]int{1, 2, 3, 4, 5}
slice5 := arr[1:4] // [2, 3, 4],长度 = 3,容量 = 4(从索引 1 到底层数组末尾)切片操作
// append 添加元素
var nameSlice []string
nameSlice = append(nameSlice, "zhangsan", "lisi")
fmt.Println(nameSlice) // [zhangsan lisi]
// 遍历并赋值
ageSlice := make([]int, 5)
for i := range ageSlice {
ageSlice[i] = i + 1
}
fmt.Println(ageSlice) // [1 2 3 4 5]切片遍历
nums := []int{10, 20, 30}
// for-range 遍历,每次返回索引和值的副本
for i, num := range nums {
fmt.Printf("索引: %d, 值: %d\n", i, num)
num *= 2 // 只修改副本,不影响原切片
}
fmt.Println(nums) // [10 20 30](未被修改)
// 若要修改原值,通过索引操作
for i := range nums {
nums[i] *= 2
}
fmt.Println(nums) // [20 40 60](已被修改)切片排序
import "sort"
ages := []int{3, 5, 12, 1, 45, 55}
// 升序
sort.Ints(ages)
fmt.Println(ages) // [1 3 5 12 45 55]
// 降序
sort.Sort(sort.Reverse(sort.IntSlice(ages)))
fmt.Println(ages) // [55 45 12 5 3 1]日常使用
import (
"fmt"
)
func main() {
// 创建动态数组
// 不用显式指定数组大小,它会根据实际存储的元素数量自动扩缩容
arr := make([]int, 0)
for i := 0; i < 10; i++ {
// 在末尾追加元素,时间复杂度 O(1)
arr = append(arr, i)
}
// 在中间插入元素,时间复杂度 O(N)
// 在索引 2 的位置插入元素 666
arr = append(arr[:2], append([]int{666}, arr[2:]...)...)
// 在头部插入元素,时间复杂度 O(N)
arr = append([]int{-1}, arr...)
// 删除末尾元素,时间复杂度 O(1)
arr = arr[:len(arr)-1]
// 删除中间元素,时间复杂度 O(N)
// 删除索引 2 的元素
arr = append(arr[:2], arr[3:]...)
// 根据索引查询元素,时间复杂度 O(1)
a := arr[0]
// 根据索引修改元素,时间复杂度 O(1)
arr[0] = 100
// 根据元素值查找索引,时间复杂度 O(N)
index := -1
for i, v := range arr {
if v == 666 {
index = i
break
}
}
}Map(映射)
Map 是无序的 key-value 对集合。使用前必须初始化。
map 初始化、添加、删除
// 1. 字面量初始化
m1 := map[string]int{
"apple": 5,
"banana": 4,
}
// 2. 空 map 初始化
m2 := map[int]string{}
// 添加
m2[1] = "zhangsan"
m2[3] = "lisi"
// 删除
delete(m2, 3)map 与切片/结构体结合
// map 值为切片类型
scores := map[string][]int{
"小明": {80, 90, 87},
"李华": {90, 78, 99},
}
// map 值为结构体类型
type User struct {
Name string
Score float32
}
users := map[int]User{
1: {"Tom", 78.6},
2: {"John", 88.9},
}map 查找
age := map[string]int{
"浩然": 20,
"梅梅": 23,
}
// 双返回值查找
value, ok := age["浩然"]
fmt.Println(value, ok) // 20 true
// 如果 key 不存在,ok 为 false
value, ok = age["不存在"]
fmt.Println(value, ok) // 0 falsemap 遍历
m := map[int]string{}
s := []string{"zhangsan", "lisi", "wangwu"}
for key, value := range s {
m[key] = value
}
fmt.Println(m) // map[0:zhangsan 1:lisi 2:wangwu]底层数据共享类型
以下类型在传递时会共享底层数据(修改影响原变量):
| 类型 | 说明 |
|---|---|
| 切片 | 复制结构(指针+长度+容量),共享底层数组 |
| Map | 复制哈希表指针 |
| 通道 | 复制通道引用 |
| 函数 | 传递函数引用 |
| 接口 | 传递动态类型和动态值的指针 |
| 指针 | 复制地址值,共享同一内存 |
