字
字节笔记本
2026年2月22日
Golang 中 range 的使用方法及注意事项
range 是 Go 语言中非常强大的迭代器,可以遍历数组、切片、字符串、map 等多种数据结构。本文将详细介绍 range 的基本用法以及使用过程中需要注意的关键点。
一、基本用法
range 类似迭代器,可以遍历数组、字符串、map 等等,对象的不同,返回的结果也不同。
go
package main
import "fmt"
func main() {
// 数组的遍历
a := [3]int{1, 2, 3}
for i, n := range a {
fmt.Println(i, n)
}
// 切片的遍历
b := []int{2, 3, 4}
for i, n := range b {
fmt.Println(i, n)
}
// map 的遍历
c := map[string]int{"Hello": 1, "World": 2}
for k, v := range c {
fmt.Println(k, v)
}
}输出结果:
text
0 1
1 2
2 3
0 2
1 3
2 4
Hello 1
World 2二、注意事项
1. range 会复制对象,而不是直接在原对象上操作
示例一:
go
package main
import "fmt"
func main() {
a := [3]int{1, 2, 3}
for _, v := range a {
// 复制一份 a 遍历 [1, 2, 3]
v += 100 // v 是复制对象中的值,不会改变 a 数组元素的值
}
fmt.Println(a) // 输出: [1 2 3]
}示例二:
go
package main
import "fmt"
func main() {
a := [3]int{1, 2, 3}
for i, v := range a {
// i, v 从 a 复制的对象里提取出
if i == 0 {
a[1], a[2] = 200, 300
fmt.Println(a) // 输出 [1 200 300]
}
a[i] = v + 100 // v 是复制对象里的元素 [1, 2, 3]
}
fmt.Println(a) // 输出 [101, 102, 103]
}2. 使用 range 迭代遍历引用类型时,底层的数据不会被复制
go
package main
import "fmt"
func main() {
a := []int{1, 2, 3} // 改成 slice
for i, v := range a {
if i == 0 {
a[1], a[2] = 200, 300
fmt.Println(a) // [1 200 300]
}
a[i] = v + 100
}
fmt.Println(a)
}输出结果:
text
[1 200 300]
[101 300 400]因为切片的内部结构为 struct slice{*point, len, cap}。
数据部分是一个指针,指向地址,复制对象的时候只是把指针的值复制了,而不是重新拷贝一块新的内存再把值放进去,所以修改的时候还是修改的原来的值,和 C++ 里的浅拷贝一样。
总结
理解 range 的复制机制对于编写正确的 Go 代码至关重要:
- 数组:range 会复制整个数组,遍历时修改的是副本
- 切片:range 只复制切片头(指针、长度、容量),底层数组共享
- map:range 返回的是键值对的副本
在实际开发中,如果需要修改原数据结构,建议使用索引直接访问,或者使用指针类型。
原文作者:马谦的博客 文章来源:Go语言中文网
分享: