Golang 语言坑之for-range

go只提供了一种循环方式,即for循环,其中有两种方式。第一种是for [initStmt];[Condition];[PostStmt]{}

for i:=0;i++;i<10{
      ....

}

 第二种是for-range可以用来历容器类型如数组、切片和映射,channel 。但是使用for-range时,如果使用不当会程序运行不是预期结果,例如,下面的示例程序将遍历一个切片,并将切片的值当成切片值存入,切片类型是一个结构体,切片的类型是为Point型,值是一个地址。

package main

import "log"

/**

    Created by GoLand
    GO Version : go1.10.3
    Project: Boring
    Created by Kaifoon
    Created with 2018/10/8 21:57

**/

type Point struct {
	x int
	y int

}

func main() {
	r := make([]*Point,4)
	d := []Point{
		{1,3},
		{3,3},
		{3,48},
		{8,2},
	}
	for _,v := range d {
		r = append(r,&v)
	}
	for _,v := range r {
		log.Println(*v)
	}
}

  我们希望结果是

2018/10/08 22:44:50 {1 3}
2018/10/08 22:44:50 {3 3}
2018/10/08 22:44:50 {3 48}
2018/10/08 22:44:50 {8 2}

Process finished with exit code 0

  但是实际运行是这样的

2018/10/08 22:44:50 {8 2}
2018/10/08 22:44:50 {8 2}
2018/10/08 22:44:50 {8 2}
2018/10/08 22:44:50 {8 2}

Process finished with exit code 0

  由输出可以知道,程序取最后迭代的值写入。经过debug发现,原来for-range 时 v 是复制切片的的值,然而v的指针地址是没变的。所以迭代完成的时候,因为读取的v的指针,v的地址被写入,装入的值也是最后迭代的值。正确程序如下:

package main

import "log"

/**

    Created by GoLand
    GO Version : go1.10.3
    Project: Boring
    Created by Kaifoon
    Created with 2018/10/8 21:57

**/

type Point struct {
	x int
	y int

}

func main() {
	r := make([]*Point,0)
	d := []Point{
		{1,3},
		{3,3},
		{3,48},
		{8,2},
	}
	for _,v := range d {
		vv := v
		r = append(r,&vv)
	}
	for _,v := range r {
		log.Println(*v)
	}
}

  

原文地址:https://www.cnblogs.com/kaifoon/p/9757830.html

时间: 2024-10-14 05:52:38

Golang 语言坑之for-range的相关文章

学习-go语言坑之for range

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

golang语言编译的二进制可执行文件为什么比 C 语言大(转载)

最近一位朋友问我"为什么同样的hello world 入门程序"为什么golang编译出来的二进制文件,比 C 大,而且大很多.我做了个测试,来分析这个问题.C 语言的hello world程序: 1 2 3 4 5 #include <stdio.h> int main() {     printf("hello world!\n");     return 0; } golang 语言的hello world程序: 1 2 3 4 5 6 7 pac

Golang语言编程规范

Golang语言编程规范 一.说明 编程规范好,可避免语言陷阱,可有利团队协作,有利项目维护. 正常的Go编程规范有两种:编译器强制的(必须的),gofmt格式化非强制的(非必须). Go宣告支持驼峰命名法,排斥下划线法. 自定义原则: a.统一工作区间,避免目录及文件名随意 b.规范变量/结构体/方法及接口名 c.规范注释 d.单元测试/程序效率等建议 两个等级: (S)建议,(M)必须.以下是细节. 二.代码组织结构 (M)一个目录只包含一个包,模块复杂拆分子模块/子目录 (S)内部项目GO

RabbitMQ官方教程一Hello World(GOLANG语言实现)

介绍 RabbitMQ是消息中间件:它接受并转发消息. 您可以将其视为邮局系统:将要发送的邮件放在邮箱中时, 可以确保邮递员最终将邮件传递给收件人. 以此类推,RabbitMQ是一个邮箱,一个邮局和一个邮递员. RabbitMQ与邮局之间的主要区别在于, 它不处理纸张,而是接收,存储和转发数据消息的二进制数据. 以下是RabbitMQ和消息发送的术语 Producer:生产者.负责生产消息. Queue:队列.负责存储消息.队列在RabbitMQ中充当邮箱的角色,消息传递到RabbitMQ中,只

学习Golang语言(6):类型--切片

学习Golang语言(1): Hello World 学习Golang语言(2): 变量 学习Golang语言(3):类型--布尔型和数值类型 学习Golang语言(4):类型--字符串 学习Golang语言(5):类型--数组 学习Golang语言(6):类型--切片 在很多应用场景中,数组不能够满足我们的需求.在初始定义数组时,我们并不知道数组所需的长度.因此,我们需要一个大小可以动态变化的数组(动态数组) 在Go语言中,这种"动态数组"成为slice(切片). 但是实际上slic

golang语言并发与并行——goroutine和channel的详细理解(一)

如果不是我对真正并行的线程的追求,就不会认识到Go有多么的迷人. Go语言从语言层面上就支持了并发,这与其他语言大不一样,不像以前我们要用Thread库 来新建线程,还要用线程安全的队列库来共享数据. 以下是我入门的学习笔记. Go语言的goroutines.信道和死锁 goroutine Go语言中有个概念叫做goroutine, 这类似我们熟知的线程,但是更轻. 以下的程序,我们串行地去执行两次loop函数: func loop() { for i := 0; i < 10; i++ { f

为什么要用golang语言进行区块链编程开发?

Go语言现在常常被用来做去中心化系统(decentralised system).其他类型的公司也都把Go用在产品的核心模块中,并且它在网站开发中也占据了一席之地. 我们在决定做Karachain的时候,考量(benchmark)了C,C++, Java, 甚至NodeJs,我们也试着用一些算法来作为考量标准.而现在,我表示我们正在用Go来实现此目标,并且感觉不错. 啊,现在建造一个区块链,恰如当时建造一个操作系统! 我们在建造像区块链平台这样复杂的东西时,把注意力放在了那些核心问题上.经过差不

golang采坑一 expected &#39;;&#39;, found &#39;import&#39;

golang变成使用IDE,注意IDE的默认换行符号 我使用的是PHPstrome IED工具,注意右下角这个默认换行符.不然,总是提示错误 expected ";",found "import".换成\r\n 就好了 golang采坑一 expected ';', found 'import' 原文地址:https://www.cnblogs.com/iifeng/p/11458311.html

golang爬坑:操作Linux命令

通常在启动项目服务程序的时候,需要判断该服务是否已经被启动,一般的做法有两种,其一是每次启动后将pid写入文件中,启动的时候读取这个文件,如果里面有数值,就表示服务已启动:另一种是通过shell命令查找: ps -ef | grep XXX | grep -v grep | awk '{print $2}' 很多语言都可以直接执行这行命令:偏偏go语言不行,因此,我们可以利用go中提供的一些方法实现它(不说了,直接上代码): func Pipeline(cmds ...*exec.Cmd) (p