编程 Golang 中你应该知道的 Range 知识

2024-11-19 04:01:21 +0800 CST views 561

Golang 中你应该知道的 Range 知识

1.1 for range 概述及使用

for range 是 Go 语言中非常常用的循环结构,用于遍历多种数据结构,例如数组、slice、map、字符串以及 channel。通过 for range,可以简洁地获取集合中的索引和值。

基本语法:

for index, value := range collection {}
  • collection: 要遍历的数据结构,如数组、切片、映射、字符串或通道。
  • index: 当前元素的索引,对于映射,索引为键 (key)。
  • value: 当前索引位置的值。

如果不需要索引,可以使用下划线 (_) 忽略:

for _, value := range collection {}

1.2 for range 使用场景

1.2.1 遍历数组

数组是固定大小的序列,for range 可以用于遍历数组的每个元素。

arr := [5]int{10, 20, 30, 40, 50}
for i, v := range arr {
    fmt.Printf("Index: %d, Value: %d\n", i, v)
}

1.2.2 遍历切片

切片是数组的引用,长度可以动态变化。for range 可以用于切片的遍历。

slice := []int{100, 200, 300, 400, 500}
for i, v := range slice {
    fmt.Printf("Index: %d, Value: %d\n", i, v)
}

1.2.3 遍历 map

for range 可以用于遍历 map 中的键值对。

m := map[string]int{"a": 1, "b": 2, "c": 3}
for key, value := range m {
    fmt.Printf("Key: %s, Value: %d\n", key, value)
}

注意map 的遍历顺序是随机的,每次执行可能不同。

1.2.4 遍历字符串

for range 可以逐个字符遍历字符串,并支持 Unicode 字符。

str := "Hello, 世界"
for i, r := range str {
    fmt.Printf("Index: %d, Rune: %c\n", i, r)
}

注意for range 遍历字符串时,处理的是 Unicode 字符(rune),而不是字节。

1.2.5 遍历 channel

for range 可以用于从通道接收数据,直到通道关闭。

ch := make(chan int, 5)
go func() {
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch)
}()

for v := range ch {
    fmt.Println(v)
}

注意

  • 通道必须关闭,否则 for range 会一直阻塞。
  • for range 会在通道关闭后自动退出循环。

1.3 for range 使用中的常见错误

错误示例 1:指针问题

type user struct {
    name string
    age  uint64
}

func main() {
    u := []user{
        {"wesley", 20},
        {"wei", 30},
        {"wesleywei", 40},
    }
    n := make([]*user, 0, len(u))
    for _, v := range u {
        n = append(n, &v)
    }
    fmt.Println(n)
    for _, v := range n {
        fmt.Println(v)
    }
}

在 Go 1.22 之前,输出会是:

[0xc00000c048 0xc00000c048 0xc00000c048]
&{wesleywei 40}
&{wesleywei 40}
&{wesleywei 40}

原因是每次循环都引用了同一个变量 v 的地址。

错误示例 2:闭包问题

func main() {
    var funcs []func()

    for i := 0; i < 3; i++ {
        funcs = append(funcs, func() {
            fmt.Println(i)
        })
    }

    for _, f := range funcs {
        f()
    }
}

在 Go 1.22 之前,输出为:

3
3
3

这是因为闭包捕获的是循环变量 i 的引用,而不是每次的值。

从 Go 1.22 开始,Go 修复了此问题,输出结果为:

0
1
2

1.4 range 的特殊用法

安全删除 map 中的元素

在 Go 中,可以安全地在 for range 循环中删除 map 中的元素。

func main() {
    d := map[string]string{
        "wesley": "wei",
        "medium": "blog",
    }
    for k := range d {
        if k == "wesley" {
            delete(d, k)
        }
    }
    fmt.Println(d)
}

输出:

map[medium:blog]

这种操作在其他语言中(如 Python 或 Java)可能会引发错误或异常。

动态添加 map 中的元素

可以在 for range 遍历 map 时动态添加元素:

func main() {
    t := map[string]string{
        "wesley":  "handsome",
        "wesley1": "handsome1",
        "wesley2": "handsome2",
    }
    for k := range t {
        t["wesley3"] = "handsome3"
        fmt.Printf("%s-%s ", k, t[k])
    }
}

每次执行的结果可能不同,原因是 map 的哈希表特性导致遍历顺序随机。

1.5 总结

for range 是 Go 语言中非常强大的循环结构,可以遍历多种类型的数据结构。通过掌握其使用场景、常见错误和特殊用法,你可以更高效地处理复杂的数据操作。

复制全文 生成海报 编程 Go语言 数据结构 循环 错误处理

推荐文章

百度开源压测工具 dperf
2024-11-18 16:50:58 +0800 CST
实现微信回调多域名的方法
2024-11-18 09:45:18 +0800 CST
js常用通用函数
2024-11-17 05:57:52 +0800 CST
2024年公司官方网站建设费用解析
2024-11-18 20:21:19 +0800 CST
Vue3中的响应式原理是什么?
2024-11-19 09:43:12 +0800 CST
初学者的 Rust Web 开发指南
2024-11-18 10:51:35 +0800 CST
MySQL 主从同步一致性详解
2024-11-19 02:49:19 +0800 CST
mysql关于在使用中的解决方法
2024-11-18 10:18:16 +0800 CST
Vue3 组件间通信的多种方式
2024-11-19 02:57:47 +0800 CST
Python 微软邮箱 OAuth2 认证 Demo
2024-11-20 15:42:09 +0800 CST
Nginx负载均衡详解
2024-11-17 07:43:48 +0800 CST
Go 1.23 中的新包:unique
2024-11-18 12:32:57 +0800 CST
随机分数html
2025-01-25 10:56:34 +0800 CST
liunx宝塔php7.3安装mongodb扩展
2024-11-17 11:56:14 +0800 CST
Golang 随机公平库 satmihir/fair
2024-11-19 03:28:37 +0800 CST
资源文档库
2024-12-07 20:42:49 +0800 CST
一键配置本地yum源
2024-11-18 14:45:15 +0800 CST
Rust 并发执行异步操作
2024-11-18 13:32:18 +0800 CST
内网穿透技术详解与工具对比
2025-04-01 22:12:02 +0800 CST
程序员茄子在线接单