设为首页 加入收藏

TOP

深入探究for...range语句(二)
2023-07-23 13:25:42 】 浏览:53
Tags:for...range 语句
因,就是由于迭代变量被复用,所有的goroutine都会共享相同的value变量。当goroutine开始执行时,它们可能会读取到最后一次迭代的结果,而不是预期的迭代顺序。这会导致输出结果可能是重复的数字或者不按照预期的顺序输出。

如果不清楚迭代变量会被复用的特点,这个在某些场景下可能会导致意料之外结果的出现。因此,如果for...range循环中存在并发操作,延迟函数等操作时,同时也依赖于迭代变量的值,这个时候需要确保在循环迭代中创建新的副本,以避免意外的结果。

4.2 参与迭代的为range表达式的副本数据

对于for...range循环,是使用range表达式的副本数据进行迭代。这意味着迭代过程中对原始数据的修改,并不会对迭代的结果造成影响,一个简单的代码示例如下:

package main

import "fmt"

func main() {
        numbers := [5]int{1, 2, 3, 4, 5}
        for i, v := range numbers {
           if i == 0 {
              numbers[1] = 100 // 修改原始数据的值
              numbers[2] = 200
           }
           fmt.Println("Index:", i, "Value:", v)
        }
}

在上述代码中,我们使用for...range循环遍历数组numbers, 然后在循环体内修改了数组中元素的值。遍历结果如下:

Index: 0 Value: 1
Index: 1 Value: 2
Index: 2 Value: 3
Index: 3 Value: 4
Index: 4 Value: 5

可以看到,虽然在迭代过程中,对numbers进行遍历,但是并没有影响到遍历的结果。从这里也可以证明,参与迭代的为range表达式的副本数据,而不是副本数据。

如果循环中的操作,需要依赖中间修改后的数据结果,此时最好分成两个遍历,首先遍历数据,修改其中的数据,之后再遍历修改后的数据。对上述代码改进如下:

numbers := [5]int{1, 2, 3, 4, 5}
// 1. 第一个遍历修改数据
for i, _ := range numbers {
   if i == 0 {
      numbers[1] = 100 // 修改原始数据的值
      numbers[2] = 200
   }

}
// 2. 第二个遍历输出数据
for i, v := range numbers {
   fmt.Println("Index:", i, "Value:", v)
}

这次遍历的结果,就是修改后的数据,如下:

Index: 0 Value: 1
Index: 1 Value: 100
Index: 2 Value: 200
Index: 3 Value: 4
Index: 4 Value: 5

4.3 map遍历顺序是不确定的

对于Go语言中的map类型,遍历其键值对时的顺序是不确定的,下面是一个简单代码的示例:

package main

import "fmt"

func main() {
        data := map[string]int{
                "apple":  1,
                "banana": 2,
                "cherry": 3,
        }

        for key, value := range data {
                fmt.Println(key, value)
        }
}

运行上述代码,每次输出的结果可能是不同的,即键值对的顺序是不确定的。有可能第一次运行的结果为:

banana 2
cherry 3
apple 1

然后第二次运行的结果又与第一次运行的结果不同,可能为:

apple 1
banana 2
cherry 3

从这个例子可以证明,对map进行遍历,其遍历顺序是不固定的,所以我们需要注意,不能依赖map的遍历顺序。

如果需要每次map中的数据按照某个顺序输出,此时可以先把key保存到切片中,对切片按照指定的顺序进行排序,之后遍历排序后的切片,并使用切片中的key来访问map中的value。此时map中的数据便能够按照指定的顺序来输出,下面是一个简单的代码代码示例:

package main

import (
        "fmt"
        "sort"
)

func main() {
        data := map[string]int{
                "apple":  1,
                "banana": 2,
                "cherry": 3,
        }

        // 创建保存键的切片
        keys := make([]string, 0, len(data))
        for key := range data {
                keys = append(keys, key)
        }

        // 对切片进行排序
        sort.Strings(keys)

        // 按照排序后的键遍历map
        for _, key := range keys {
                value := data[key]
                fmt.Println(key, value)
        }
}

5. 总结

本文对Go语言中的for...range进行了基本介绍,首先从一个简单遍历问题出发,发现基本的for语句似乎无法简单实现对stringmap等类型的遍历操作,从而引出了for...range语句。

接着我们仔细介绍了,如何使用for...rangestring,map,channel等类型的遍历操作。然后我们再仔细介绍了使用for...range的三个注意事项,如参与迭代的为range表达式的副本数据。通过对这些注意事项的了解,我们能够更好得使用for...range语句,避免出现预料之外的情况。

基于以上内容,完成了对for...range的介绍,希望能帮助你更好地理解和使用这个重要的Go语言特性。

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇翻车了,被读者找出 BUG 下一篇【解决一个小问题】golang 的 `-r..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目