坑一:迭代时协程引用索引和值

先看看下面的例子,你知道最终输出的结果是什么吗?

package main

import (
"fmt"
"time"
) func main() {
var m = []int{1, 3, 5}
for i, v := range m {
go func() {
fmt.Println(i, v)
}()
}
time.Sleep(time.Second)
}

不知道的同学,大家可以在 https://play.golang.org/ 这里尝试运行一下。

正确答案是:

2 5
2 5
2 5

这是为啥?三个 goroutine 都是输出了最后迭代的索引和值。

我觉得,理解清楚以下两点就可以了:

  1. 闭包内引用了外部变量 i 和 v,三个协程都引用了
  2. 协程运行时,循环可能已经结束了

要想解决这个问题,可以改成闭包传参的形式:

func main() {
var m = []int{1, 3, 5}
for i, v := range m {
go func(_i, _v int) {
fmt.Println(_i, _v)
}(i, v)
}
time.Sleep(time.Second)
}

也可以让每一轮循环都用新的变量:

func main() {
var m = []int{1, 3, 5}
for i, v := range m {
_i := i
_v := v
go func() {
fmt.Println(_i, _v)
}()
}
time.Sleep(time.Second)
}

运行结果就符合预期了:

0 1
1 3
2 5

坑二:迭代时值为原先迭代对象的拷贝

package main

import (
"fmt"
) func main() {
var m = []int{1, 3, 5}
for i, v := range m {
if i == 1 {
v = 2
}
fmt.Println(i, v)
}
fmt.Println(m)
}

这个输出是啥?

0 1
1 2 // 明明改成 2 了,
2 5
[1 3 5] // 这里还是 3 ?

那是因为,Go 会在 range 循环中自动为遍历的对象创造一个副本,可以理解为一个值拷贝,如果真的想修改原数组,你得这样写:

func main() {
var m = []int{1, 3, 5}
for i, v := range m {
if i == 1 {
m[i] = 2 // 改成 m[i]
}
fmt.Println(i, v)
}
fmt.Println(m)
}

程序输出是这样:

0 1
1 3 // 由于是值拷贝,所以改了原来的 m[i] 不影响 v 的值,m[i]=2,v=3.
2 5
[1 2 5] // 可以看到已经改成 2 了

也不算是什么大坑,理解了感觉和 PHP 的 foreach 语法差不多。


文章来源于本人博客,发布于 2019-06-16,原文链接:https://imlht.com/archives/187/

Go 语言 for-range 的两个坑,你踩过吗?的更多相关文章

  1. go语言之range

    Go 语言范围(Range) Go 语言中 range 关键字用于 for 循环中迭代数组(array).切片(slice).通道(channel)或集合(map)的元素.在数组和切片中它返回元素的索 ...

  2. 两个坑-Linux下Network-Manager有线未托管-DNS resolv.conf文件开机被清空

    Linux里面有两套管理网络连接的方案: 1./etc/network/interfaces(/etc/init.d/networking) 2.Network-Manager 两套方案是冲突的,不能 ...

  3. iscroll遇到的两个坑

    最近移动端闪付遇到的两个坑做下总结: 1.使用iscroll后,滑动并没有生效 解决方案: 首先要查看:结构是否正确: <div id="wrapper">   //w ...

  4. R语言·文本挖掘︱Rwordseg/rJava两包的安装(安到吐血)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- R语言·文本挖掘︱Rwordseg/rJava ...

  5. 记自己在spring中使用redis遇到的两个坑

    本人在spring中使用redis作为缓存时,遇到两个坑,现在记录如下,算是作为自己的备忘吧,文笔不好,望大家见谅: 一.配置文件 <!-- 加载Properties文件 --> < ...

  6. MySql 5.7安装(随机密码,修改默认密码)两个坑

    MySql 5.7安装(随机密码,修改默认密 下载了MySql 最新版本,安装的过程中,发现了很多新特性 1.data目录不见了 在进行my-default.ini配置的时候 (需要配置 # base ...

  7. Go语言结构体转json的坑

    Go语言结构体转json的坑 标签(空格分隔): go json.Marshal() JSON输出的时候必须注意,只有导出的字段(首字母是大写)才会被输出,如果修改字段名,那么就会发现什么都不会输出, ...

  8. 论nw.js的坑~~~感觉我所有的前端能遇到的坑都踩了一遍

    先总结:nw.js 真特么的...难用...文档,我得先百度才能看的稍微明白点文档......!!!!!!我感觉我所有的前端能遇到的坑都踩了一遍,此文针对前后端分离项目,别的先不说 一.不需要在项目里 ...

  9. go语言---for range

    学习-go语言坑之for range https://www.cnblogs.com/hetonghai/p/6718250.html go只提供了一种循环方式,即for循环,在使用时可以像c那样使用 ...

  10. 【转】C语言宏定义的几个坑和特殊用法

    总结一下C语言中宏的一些特殊用法和几个容易踩的坑.由于本文主要参考GCC文档,某些细节(如宏参数中的空格是否处理之类)在别的编译器可能有细微差别,请参考相应文档. 宏基础 宏仅仅是在C预处理阶段的一种 ...

随机推荐

  1. python-pygal

    准备写大作业的时候发现了一个绝绝子的python库. 原文:https://blog.damavis.com/en/creating-vector-graphics-with-python/ 官网:h ...

  2. Prism Sample 6 Activation Deactivation

    例5中刚说到视图精确控制,这次说明这样的灵活控制是怎样做的,显示或不显示,或切换视图. 主页上显示了主按钮和一个ContentControl <DockPanel LastChildFill=& ...

  3. Vite-WeGPT聊天AI实例|vue3+pinia仿ChatGPT聊天界面

    基于vue3.x+vite4+pinia2仿chatgpt聊天模拟实例Vue3-WeGPT. 基于Vite4.x+Vue3+Pinia2+VEPlus+Vue3-Markdown等技术实现仿ChatG ...

  4. Vue中使用原生js实现轮播图滑动效果

    1.在视图层模板里面绑定touchstart和touchend事件 <div class="tuWap" @touchstart="touchStart" ...

  5. 音视频八股文(3)--ffmpeg常见命令(2)

    07-ffplay命令播放媒体 播放本地文件 播放本地 MP4 视频文件 test.mp4 的命令,从第 2 秒位置开始播放,播放时长为 10 秒,并且在窗口标题中显示 "test time ...

  6. 2022-11-09:给定怪兽的血量为hp 第i回合如果用刀砍,怪兽在这回合会直接掉血,没有后续效果 第i回合如果用毒,怪兽在这回合不会掉血, 但是之后每回合都会掉血,并且所有中毒的后续效果会叠加 给

    2022-11-09:给定怪兽的血量为hp 第i回合如果用刀砍,怪兽在这回合会直接掉血,没有后续效果 第i回合如果用毒,怪兽在这回合不会掉血, 但是之后每回合都会掉血,并且所有中毒的后续效果会叠加 给 ...

  7. docker安装kibana,报错Kibana server is not ready yet,未解决

    1.命令 docker run -d -e ELASTICSEARCH_URL=http://192.168.101.158:9200 -p 5601:5601 --name kibana kiban ...

  8. es笔记四之中文分词插件安装与使用

    本文首发于公众号:Hunter后端 原文链接:es笔记四之中文分词插件安装与使用 前面我们介绍的操作及演示都是基于英语单词的分词,但我们大部分使用的肯定都是中文,所以如果需要使用分词的操作肯定也是需要 ...

  9. [vuex] unknown action type:***

    vuex 分模块后使用mapActions调用action老是提示 [vuex] unknown action type:*** 异常 目录 index.js是这样的 import Vue from ...

  10. Flutter热更新技术探索

    一,需求背景: APP发布到市场后,难免会遇到严重的BUG阻碍用户使用,因此有在不发布新版本APP的情况下使用热更新技术立即修复BUG需求.原生APP(例如:Android & IOS)的热更 ...