在 Go 语言中,range
关键字用于迭代遍历数组(array)、切片(slice)、映射(map)、字符串(string)和通道(channel)中的元素。它的基本语法和用法如下:
nums := []int{2, 3, 4}
// 同时获取索引和值
for index, value := range nums {
fmt.Printf(“索引: %d, 值: %d\n”, index, value)
}
// 仅获取索引
for index := range nums {
fmt.Printf(“索引: %d\n”, index)
}
// 仅获取值(用 _ 忽略索引)
for _, value := range nums {
fmt.Printf(“值: %d\n”, value)
}
m := map[string]int{“a”: 1, “b”: 2}
// 遍历键值对
for key, value := range m {
fmt.Printf(“键: %s, 值: %d\n”, key, value)
}
// 仅遍历键
for key := range m {
fmt.Printf(“键: %s\n”, key)
}
// 注意:Map 的遍历顺序是随机的!
s := “hello”
// 遍历字符串的 Unicode 码点(rune)
for index, char := range s {
fmt.Printf(“索引: %d, Unicode值: %U, 字符: %c\n”, index, char, char)
}
// 输出:
// 索引: 0, Unicode值: U+0068, 字符: h
// 索引: 1, Unicode值: U+0065, 字符: e
// …
ch := make(chan int)
go func() {
ch <- 1
ch <- 2
close(ch) // 必须关闭通道,否则 range 会阻塞
}()
// 从通道持续接收值,直到通道关闭
for value := range ch {
fmt.Printf(“值: %d\n”, value)
}
值拷贝
range
返回的是元素的副本,修改副本不会影响原数据:
nums := []int{1, 2, 3}
for _, v := range nums {
v *= 2 // 不影响原切片
}
fmt.Println(nums) // 输出 [1 2 3]
引用类型陷阱
如果遍历指针类型的切片,需注意循环变量的生命周期:
type Data struct{ val int }
list := []*Data{{1}, {2}, {3}}
var pointers []*int
// 错误写法:所有指针指向最后一个元素的地址!
for _, d := range list {
pointers = append(pointers, &d.val)
}
// 正确写法:用局部变量拷贝
for i := range list {
val := list[i].val
pointers = append(pointers, &val)
}
性能优化
遍历大数组时,直接通过索引访问可能比 range
更高效(但差异通常很小)。
range
支持数组、切片、map、字符串和通道的遍历。_
)。