go语言坑之for range

04 Apr 2017 go语言坑之for range

go只提供了一种循环方式,即for循环,在使用时可以像c那样使用,也可以通过for range方式遍历容器类型如数组、切片和映射。但是在使用for range时,如果使用不当,就会出现一些问题,导致程序运行行为不如预期。比如,下面的示例程序将遍历一个切片,并将切片的值当成映射的键和值存入,切片类型是一个int型,映射的类型是键为int型,值为*int,即值是一个地址。

package main

import "fmt"

func main() {
    slice := []int{0, 1, 2, 3}
    myMap := make(map[int]*int)

    for index, value := range slice {
        myMap[index] = &value
    }
    fmt.Println("=====new map=====")
    prtMap(myMap)
}

func prtMap(myMap map[int]*int) {
    for key, value := range myMap {
        fmt.Printf("map[%v]=%v\n", key, *value)
    }
}

运行程序输出如下:

=====new map=====
map[3]=3
map[0]=3
map[1]=3
map[2]=3

由输出可以知道,不是我们预期的输出,正确输出应该如下:

=====new map=====
map[0]=0
map[1]=1
map[2]=2
map[3]=3

但是由输出可以知道,映射的值都相同且都是3。其实可以猜测映射的值都是同一个地址,遍历到切片的最后一个元素3时,将3写入了该地址,所以导致映射所有值都相同。其实真实原因也是如此,因为for range创建了每个元素的副本,而不是直接返回每个元素的引用,如果使用该值变量的地址作为指向每个元素的指针,就会导致错误,在迭代时,返回的变量是一个迭代过程中根据切片依次赋值的新变量,所以值的地址总是相同的,导致结果不如预期。

修正后程序如下:

package main

import "fmt"

func main() {
    slice := []int{0, 1, 2, 3}
    myMap := make(map[int]*int)

    for index, value := range slice {
        num := value
        myMap[index] = &num
    }
    fmt.Println("=====new map=====")
    prtMap(myMap)
}

func prtMap(myMap map[int]*int) {
    for key, value := range myMap {
        fmt.Printf("map[%v]=%v\n", key, *value)
    }
}

运行程序输出如下:

=====new map=====
map[2]=2
map[3]=3
map[0]=0
map[1]=1
本次荐书:算法图解

LEo at 11:13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏mySoul

DOM概述 选取文档元素

有些html标签会有name元素,区别于id,name属性的值不必是唯一的,多个元素可能存在相同的名字。

986
来自专栏用户画像

H5中的标记方法

要使用H5标记,必须先进行如下的doctype声明,不区分大小写。Web浏览器通过判断文件开头有没有这个声明,来判断解析器和渲染类型是否切换到对应的H5模式。

811
来自专栏前端知识分享

第11天:JS中变量、字符串基础知识

js页面效果:轮播图、选项卡、地图、表单验证javascript是弱变量类型的语言,变量只需要用var来声明。而java要根据变 量类型来声明,

3473
来自专栏小壮和前端

js写插件教程

2171
来自专栏IMWeb前端团队

vue.js笔记——指令

vue.js笔记——指令 跟ng的指令系统类似,vue也拥有一套指令系统。 所谓指令,其实本质就是在模板中出现的特殊标记,根据这些标记让框架知道需要对这里的 D...

2209
来自专栏大史住在大前端

javascript基础修炼(3)—What's this(下)

严格模式是ES5中添加的javascript的另一种运行模式,它可以禁止使用一些语法上不合理的部分,提高编译和运行速度,但语法要求也更为严格,使用use str...

1092
来自专栏HTML5学堂

2015.12.24 HTML5真题练习

HTML5学堂:各位,圣诞快乐~!!!每天一道题,强壮程序员!今日主要涉及12.23日关于逗号运算符和for循环知识的题目解答,以及一道涉及逗号运算符的题目。 ...

2795
来自专栏十月梦想

ES6函数res参数和ES5函数参数(arguments)

在JavaScript ES5中我们可以使用arguments对象获取参数的所有

2651
来自专栏源哥的专栏

给textarea增加长度的限制

给textarea增加长度的限制     我们知道文本框可以有一个为maxlength的属性,可以限制文本框的长度,当时备注框textarea却没有,那么 要怎...

932
来自专栏小狼的世界

JavaScript 去除空格函数

return strToTrim.replace(/^\s+|\s+$/g,"")

1253

扫码关注云+社区

领取腾讯云代金券