#Go Range
range is a keyword in Go used to iterate over various data structures. It provides a concise, unified way to iterate over arrays, slices, strings, maps, and channels.
#📋 Range Basic Syntax
#Basic Syntax Format
// 基本格式
for index, value := range collection {
// 处理 index 和 value
}
// 只需要索引
for index := range collection {
// 只处理 index
}
// 只需要值
for _, value := range collection {
// 只处理 value,使用 _ 忽略索引
}
// 只迭代,不需要索引和值
for range collection {
// 只是迭代,不使用索引和值
}#📚 Iterating Over Arrays and Slices
#Iterating Over Arrays
package main
import "fmt"
func main() {
// 定义数组
numbers := [5]int{10, 20, 30, 40, 50}
fruits := [3]string{"苹果", "香蕉", "橙子"}
// 完整遍历:索引和值
fmt.Println("=== 遍历数字数组 ===")
for index, value := range numbers {
fmt.Printf("索引: %d, 值: %d\n", index, value)
}
// 只遍历值
fmt.Println("\n=== 只遍历值 ===")
for _, fruit := range fruits {
fmt.Printf("水果: %s\n", fruit)
}
// 计算数组元素总和
sum := 0
for _, num := range numbers {
sum += num
}
fmt.Printf("\n数组总和: %d\n", sum)
// 查找特定元素
target := 30
for i, num := range numbers {
if num == target {
fmt.Printf("找到 %d 在索引 %d\n", target, i)
break
}
}
}#Iterating Over Slices
package main
import "fmt"
func main() {
// 创建切片
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []string{"Go", "Python", "Java"}
// 遍历整数切片
fmt.Println("=== 遍历整数切片 ===")
for i, v := range slice1 {
fmt.Printf("slice1[%d] = %d\n", i, v)
}
// 动态修改切片
fmt.Println("\n=== 修改切片元素 ===")
for i := range slice1 {
slice1[i] = slice1[i] * 2 // 将每个元素乘以2
}
fmt.Printf("修改后的切片: %v\n", slice1)
// 过滤切片元素
var evenNumbers []int
for _, num := range slice1 {
if num%4 == 0 { // 找出能被4整除的数
evenNumbers = append(evenNumbers, num)
}
}
fmt.Printf("能被4整除的数: %v\n", evenNumbers)
}#🔤 Iterating Over Strings
#String Iteration
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
// 英文字符串
english := "Hello"
fmt.Println("=== 遍历英文字符串 ===")
for i, char := range english {
fmt.Printf("索引: %d, 字符: %c, Unicode: %U\n", i, char, char)
}
// 中文字符串
chinese := "你好世界"
fmt.Println("\n=== 遍历中文字符串 ===")
for i, char := range chinese {
fmt.Printf("字节索引: %d, 字符: %c, Unicode: %U\n", i, char, char)
}
// 字符串统计
text := "Go语言"
fmt.Printf("\n字符串: %s\n", text)
fmt.Printf("字节长度: %d\n", len(text))
fmt.Printf("字符长度: %d\n", utf8.RuneCountInString(text))
// 查找特定字符
target := '语'
for i, char := range text {
if char == target {
fmt.Printf("找到字符 '%c' 在字节位置 %d\n", target, i)
break
}
}
}#String Processing Examples
package main
import (
"fmt"
"unicode"
)
// 统计字符串中各种字符的数量
func analyzeString(s string) {
var letters, digits, spaces int
for _, char := range s {
switch {
case unicode.IsLetter(char):
letters++
case unicode.IsDigit(char):
digits++
case unicode.IsSpace(char):
spaces++
}
}
fmt.Printf("字符串: \"%s\"\n", s)
fmt.Printf("字母: %d, 数字: %d, 空格: %d\n", letters, digits, spaces)
}
// 反转字符串(支持中文)
func reverseString(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
func main() {
// 字符串分析
analyzeString("Hello World 123!")
analyzeString("Go语言编程 2023年")
// 字符串反转
fmt.Println("\n=== 字符串反转 ===")
texts := []string{"Hello", "Go语言", "12345"}
for _, text := range texts {
reversed := reverseString(text)
fmt.Printf("原文: %s -> 反转: %s\n", text, reversed)
}
}#🗺️ Iterating Over Maps
#Basic Map Iteration
package main
import (
"fmt"
"sort"
)
func main() {
// 创建映射
scores := map[string]int{
"Alice": 95,
"Bob": 87,
"Charlie": 92,
"Diana": 98,
}
// 基本遍历:键和值
fmt.Println("=== 遍历学生成绩 ===")
for name, score := range scores {
fmt.Printf("学生: %s, 成绩: %d\n", name, score)
}
// 计算统计信息
var total, count int
var highest int
var topStudent string
for name, score := range scores {
total += score
count++
if score > highest {
highest = score
topStudent = name
}
}
average := float64(total) / float64(count)
fmt.Printf("\n总分: %d, 平均分: %.2f\n", total, average)
fmt.Printf("最高分: %d (%s)\n", highest, topStudent)
// 按键排序遍历
fmt.Println("\n=== 按姓名排序 ===")
var names []string
for name := range scores {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
fmt.Printf("学生: %s, 成绩: %d\n", name, scores[name])
}
}#📡 Iterating Over Channels
#Channel Iteration
package main
import (
"fmt"
"time"
)
func main() {
// 创建通道
ch := make(chan int, 5)
// 发送数据到通道
go func() {
for i := 1; i <= 5; i++ {
ch <- i
fmt.Printf("发送: %d\n", i)
time.Sleep(100 * time.Millisecond)
}
close(ch) // 关闭通道
}()
// 使用 range 遍历通道
fmt.Println("=== 遍历通道 ===")
for value := range ch {
fmt.Printf("接收: %d\n", value)
}
fmt.Println("通道已关闭,遍历结束")
}#🎯 Range Pitfalls and Notes
#Value Copy Pitfall
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
people := []Person{
{"Alice", 25},
{"Bob", 30},
}
fmt.Println("=== 值拷贝陷阱 ===")
// 错误的做法:尝试修改拷贝的值
fmt.Println("错误方式(修改拷贝):")
for _, person := range people {
person.Age += 1 // 修改的是拷贝,不是原始数据
}
fmt.Println("原始数据未改变:")
for _, person := range people {
fmt.Printf("%s, 年龄: %d\n", person.Name, person.Age)
}
// 正确的做法:使用索引修改
fmt.Println("\n正确方式(使用索引):")
for i := range people {
people[i].Age += 1
}
fmt.Println("原始数据已改变:")
for _, person := range people {
fmt.Printf("%s, 年龄: %d\n", person.Name, person.Age)
}
}#Closure Pitfall
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("=== 闭包陷阱 ===")
// 错误的做法:闭包捕获循环变量
var funcs []func()
for _, name := range []string{"Alice", "Bob", "Charlie"} {
funcs = append(funcs, func() {
fmt.Printf("错误方式: %s\n", name) // 所有闭包都会打印最后一个值
})
}
fmt.Println("错误的闭包结果:")
for _, f := range funcs {
f()
}
// 正确的做法:传递参数
funcs = nil
for _, name := range []string{"Alice", "Bob", "Charlie"} {
funcs = append(funcs, func(n string) func() {
return func() {
fmt.Printf("正确方式: %s\n", n)
}
}(name))
}
fmt.Println("\n正确的闭包结果:")
for _, f := range funcs {
f()
}
// Goroutine 闭包陷阱
fmt.Println("\nGoroutine 中的应用:")
// 正确方式:传递参数给 goroutine
for _, name := range []string{"Alice", "Bob", "Charlie"} {
go func(n string) {
time.Sleep(10 * time.Millisecond)
fmt.Printf("Goroutine: %s\n", n)
}(name)
}
time.Sleep(50 * time.Millisecond)
}#🛠️ Range Practical Examples
#Data Statistics and Analysis
package main
import "fmt"
// 学生成绩统计
func analyzeScores(scores map[string]int) {
if len(scores) == 0 {
fmt.Println("没有成绩数据")
return
}
var total, count int
var max, min int
var maxStudent, minStudent string
// 初始化最大最小值
first := true
for name, score := range scores {
if first {
max, min = score, score
maxStudent, minStudent = name, name
first = false
}
total += score
count++
if score > max {
max = score
maxStudent = name
}
if score < min {
min = score
minStudent = name
}
}
average := float64(total) / float64(count)
fmt.Println("=== 成绩统计 ===")
fmt.Printf("学生人数: %d\n", count)
fmt.Printf("平均分: %.2f\n", average)
fmt.Printf("最高分: %d (%s)\n", max, maxStudent)
fmt.Printf("最低分: %d (%s)\n", min, minStudent)
// 分级统计
excellent, good, pass, fail := 0, 0, 0, 0
for _, score := range scores {
switch {
case score >= 90:
excellent++
case score >= 80:
good++
case score >= 60:
pass++
default:
fail++
}
}
fmt.Printf("优秀(90+): %d人\n", excellent)
fmt.Printf("良好(80-89): %d人\n", good)
fmt.Printf("及格(60-79): %d人\n", pass)
fmt.Printf("不及格(<60): %d人\n", fail)
}
// 单词频率统计
func wordFrequency(text string) map[rune]int {
frequency := make(map[rune]int)
for _, char := range text {
if char != ' ' { // 忽略空格
frequency[char]++
}
}
return frequency
}
func main() {
// 成绩统计示例
scores := map[string]int{
"张三": 95,
"李四": 87,
"王五": 92,
"赵六": 78,
"钱七": 96,
}
analyzeScores(scores)
// 字符频率统计
fmt.Println("\n=== 字符频率统计 ===")
text := "Hello World Go语言"
freq := wordFrequency(text)
fmt.Printf("文本: %s\n", text)
fmt.Println("字符频率:")
for char, count := range freq {
fmt.Printf(" '%c': %d次\n", char, count)
}
}#🎓 Summary
In this chapter, we comprehensively learned about Go's range keyword:
- ✅ Basic syntax: various forms of for-range usage
- ✅ Data iteration: arrays, slices, strings, maps, channels
- ✅ String processing: Unicode character iteration and handling
- ✅ Common pitfalls: value copy and closure pitfalls
- ✅ Practical applications: data statistics and analysis examples
range is a very important and commonly used feature in Go. Mastering its correct usage is essential for writing efficient Go code.
Next, we will learn about Go Recursive Functions and explore the power of recursive programming.
::: tip Range Usage Tips
- Watch out for value copy issues; use index when you need to modify original data
- Avoid directly referencing loop variables in closures
- When iterating over strings, note the byte index of Unicode characters
- Use range reasonably to improve code readability :::