Go 语言 for-range 的两个坑,你踩过吗?
坑一:迭代时协程引用索引和值
先看看下面的例子,你知道最终输出的结果是什么吗?
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 都是输出了最后迭代的索引和值。
我觉得,理解清楚以下两点就可以了:
- 闭包内引用了外部变量 i 和 v,三个协程都引用了
- 协程运行时,循环可能已经结束了
要想解决这个问题,可以改成闭包传参的形式:
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 的两个坑,你踩过吗?的更多相关文章
- go语言之range
Go 语言范围(Range) Go 语言中 range 关键字用于 for 循环中迭代数组(array).切片(slice).通道(channel)或集合(map)的元素.在数组和切片中它返回元素的索 ...
- 两个坑-Linux下Network-Manager有线未托管-DNS resolv.conf文件开机被清空
Linux里面有两套管理网络连接的方案: 1./etc/network/interfaces(/etc/init.d/networking) 2.Network-Manager 两套方案是冲突的,不能 ...
- iscroll遇到的两个坑
最近移动端闪付遇到的两个坑做下总结: 1.使用iscroll后,滑动并没有生效 解决方案: 首先要查看:结构是否正确: <div id="wrapper"> //w ...
- R语言·文本挖掘︱Rwordseg/rJava两包的安装(安到吐血)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- R语言·文本挖掘︱Rwordseg/rJava ...
- 记自己在spring中使用redis遇到的两个坑
本人在spring中使用redis作为缓存时,遇到两个坑,现在记录如下,算是作为自己的备忘吧,文笔不好,望大家见谅: 一.配置文件 <!-- 加载Properties文件 --> < ...
- MySql 5.7安装(随机密码,修改默认密码)两个坑
MySql 5.7安装(随机密码,修改默认密 下载了MySql 最新版本,安装的过程中,发现了很多新特性 1.data目录不见了 在进行my-default.ini配置的时候 (需要配置 # base ...
- Go语言结构体转json的坑
Go语言结构体转json的坑 标签(空格分隔): go json.Marshal() JSON输出的时候必须注意,只有导出的字段(首字母是大写)才会被输出,如果修改字段名,那么就会发现什么都不会输出, ...
- 论nw.js的坑~~~感觉我所有的前端能遇到的坑都踩了一遍
先总结:nw.js 真特么的...难用...文档,我得先百度才能看的稍微明白点文档......!!!!!!我感觉我所有的前端能遇到的坑都踩了一遍,此文针对前后端分离项目,别的先不说 一.不需要在项目里 ...
- go语言---for range
学习-go语言坑之for range https://www.cnblogs.com/hetonghai/p/6718250.html go只提供了一种循环方式,即for循环,在使用时可以像c那样使用 ...
- 【转】C语言宏定义的几个坑和特殊用法
总结一下C语言中宏的一些特殊用法和几个容易踩的坑.由于本文主要参考GCC文档,某些细节(如宏参数中的空格是否处理之类)在别的编译器可能有细微差别,请参考相应文档. 宏基础 宏仅仅是在C预处理阶段的一种 ...
随机推荐
- vue项目中使用lottie动画
一,安装vue-lottie 1 npm install --save vue-lottie 二,引用vue-lottie 在main.js引入并全局注册组件也可在页面单独引用 1 import lo ...
- JavaFx 生成二维码工具类封装
原文地址: JavaFx 生成二维码工具类封装 - Stars-One的杂货小窝 之前星之音乐下载器有需要生成二维码功能,当时用的是一个开源库来实现的,但是没过多久,发现那个库依赖太多,有个http- ...
- 2020-09-14:KVM和XEN虚拟化的区别?
福哥答案2020-09-14:#福大大架构师每日一题#[答案来自此链接](https://bbs.csdn.net/topics/397671000)KVM:1.虚拟化支持:全虚拟化.2.支持架构:虚 ...
- 2022-05-20:给定一个正数数组arr,长度为N,依次代表N个任务的难度,给定一个正数k, 你只能从0任务开始,依次处理到N-1号任务结束,就是一定要从左往右处理任务, 只不过,难度差距绝对值不
2022-05-20:给定一个正数数组arr,长度为N,依次代表N个任务的难度,给定一个正数k, 你只能从0任务开始,依次处理到N-1号任务结束,就是一定要从左往右处理任务, 只不过,难度差距绝对值不 ...
- Spring Boot 配置文件总结
前言 Spring Boot 中提供一个全局的配置文件:application.properties,这个配置文件的作用就是,允许我们通过这个配置文件去修改 Spring Boot 自动配置的默认值. ...
- 一个.Net开发的功能强大、易于使用的流媒体服务器和管理系统
推荐一个视频管理系统,非常适合个人或者公司打造视频网站. 项目简介 这是基于.Net Core开发的,跨平台的开源项目:支持多种音视频格式,如MP3.MP4.AVI.WMV.FLV等:支持本地管理与远 ...
- AcWing 1019. 庆功会
为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员. 期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力. 输入格式 第一行二个数n,m,其中n代表 ...
- 代码随想录算法训练营Day17二叉树|110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和
优先掌握递归 110.平衡二叉树 题目链接:110.平衡二叉树 给定一个二叉树,判断它是否是高度平衡的二叉树. 本题中,一棵高度平衡二叉树定义为: 一个二叉树_每个节点_ 的左右两个子树的高度差的绝对 ...
- 2023-05-27:给你一个只包含小写英文字母的字符串 s 。 每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换。 请你返回将 s 变成回文串的 最少操作次数 。 注意 ,输入数据
2023-05-27:给你一个只包含小写英文字母的字符串 s . 每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换. 请你返回将 s 变成回文串的 最少操作次数 . 注意 ,输入数据 ...
- How to boot the Raspberry Pi system from a USB Mass Storage Device All In One
How to boot the Raspberry Pi system from a USB Mass Storage Device All In One 如何从 USB 启动树莓派引导系统 / 如何 ...