切片:可以伸缩的数组
Go 里的数组长度是写死的,真正天天用的是切片(slice)。切片不用提前定死长度,用 make 创建,用 append 往里加元素。
package main
import "fmt"
func main() {
// make(类型, 初始长度):创建一个装 int 的切片
nums := make([]int, 3) // [0 0 0],未赋值的元素是零值
nums[0] = 10
// append 追加元素,必须用返回值接住
nums = append(nums, 40, 50)
fmt.Println(nums) // 输出: [10 0 0 40 50]
fmt.Println(len(nums)) // 输出: 5,当前元素个数
}
两个新手最容易踩的点:
append的返回值必须重新赋给原变量,直接写append(nums, 1)是无效的;len()是长度,cap()是容量,容量不够时 Go 会自动扩容,平时不用管。
切片还能从一个已有的切片上"切"出一块,语法是 [起始:结束),左闭右开:
lang := []string{"Go", "Java", "Python", "C++"}
fmt.Println(lang[1:3]) // 输出: [Java Python],取下标 1、2
fmt.Println(lang[:2]) // 输出: [Go Java],从头取到下标 2 之前
map:键值对容器
map 用来存"键 → 值"的映射,声明时写清楚键类型和值类型:
package main
import "fmt"
func main() {
age := map[string]int{
"小明": 18,
"小红": 20,
}
age["小刚"] = 22 // 新增或覆盖
fmt.Println(age["小红"]) // 输出: 20
delete(age, "小明") // 删除键值对
fmt.Println(age) // 输出: map[小刚:22 小红:20]
}
查一个可能不存在的键时,用"逗号 ok"写法判断键是否存在,避免拿到零值还蒙在鼓里:
v, ok := age["老王"]
if !ok {
fmt.Println("老王不在表里") // 输出: 老王不在表里
} else {
fmt.Println(v)
}
注意:map 遍历时的顺序是随机的,别指望每次输出顺序一样;需要有序就先把键排序。
range:统一的遍历写法
切片和 map 都用 for range 遍历。切片拿到的是"下标和值",map 拿到的是"键和值":
package main
import "fmt"
func main() {
langs := []string{"Go", "Python", "Java"}
for i, v := range langs {
fmt.Println(i, v)
// 输出: 0 Go
// 输出: 1 Python
// 输出: 2 Java
}
scores := map[string]int{"语文": 90, "数学": 95}
for k, v := range scores {
fmt.Println(k, "=", v)
}
}
只要下标不要值时,写成 for _, v := range,用空占位符 _ 忽略下标,这是 Go 的惯用写法。
小结
- 切片用
make([]T, n)创建,append追加元素且要用返回值接住; - 切片支持
[起:止)的子切片写法,左闭右开; - map 是键值对容器,
delete删除键,"逗号 ok"判断键是否存在,遍历顺序随机; for range一套写法通吃切片和 map,_用来忽略不需要的返回值。
把这三样练熟,Go 里八成的数据操作就都有抓手了,下一步可以看看结构体和方法。