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

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

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语言 数据结构 循环 错误处理

推荐文章

页面不存在404
2024-11-19 02:13:01 +0800 CST
对多个数组或多维数组进行排序
2024-11-17 05:10:28 +0800 CST
Vue3中的v-slot指令有什么改变?
2024-11-18 07:32:50 +0800 CST
php使用文件锁解决少量并发问题
2024-11-17 05:07:57 +0800 CST
如何优化网页的 SEO 架构
2024-11-18 14:32:08 +0800 CST
浅谈CSRF攻击
2024-11-18 09:45:14 +0800 CST
IP地址获取函数
2024-11-19 00:03:29 +0800 CST
php 连接mssql数据库
2024-11-17 05:01:41 +0800 CST
java MySQL如何获取唯一订单编号?
2024-11-18 18:51:44 +0800 CST
Redis函数在PHP中的使用方法
2024-11-19 04:42:21 +0800 CST
程序员茄子在线接单