golang闭包和range,关于闭包内使用外部变量

摘要:
类似地,如果不是defer,使用go,并且同时执行闭包函数,则可以首先更改主线程的值,并且y地址的值将由外出的线程使用,y的值将更改

遇到经典问题

func mian()  {
	resslice := []int{1, 2, 3, 4}
	for _, v := range resslice {
		fmt.Println(v)
		defer fun1(v)

	}

}

func fun1(value int)  {
	fmt.Println(value)

}

  输出结果为

1
2
3
4
4
3
2
1

正常传递参数,值传递,运行到defer时把当时的v值传递给函数,最后结束时按defer规律执行

resslice := []int{1, 2, 3, 4}
	for _, v := range resslice {
		fmt.Println(v)
		defer func() {
			fmt.Println(v)
		}()

	}

  改为闭包输出结果为

1
2
3
4
4
4
4
4

for range的内部大概是这样

for_temp := v
len_temp := len(for_temp)
for index_temp = 0; index_temp < len_temp; index_temp++ {
        value_temp = for_temp[index_temp]
        index = index_temp
        value = value_temp
        v = append(v, index)
}

  循环前把值复制给 for_temp 然后用同一个变量进行赋值

因为闭包里的非传递参数外部变量值是传引用的,是闭包是地址引用

闭包的v 引用外部变量v,把外部的v地址拷贝了一份,执行到最后v的值是4,所以最后输出为连续的4

增加例子方便理解

package main

import "fmt"

func main() {
    x, y := 1, 2

    defer func(a int) { 
        fmt.Printf("x:%d,y:%d
", a, y)  // y 为闭包引用
    }(x)      // 复制 x 的值

    x += 100
    y += 100
    fmt.Println(x, y)
}

  输出结果

101 102
x:1,y:102
闭包不加接收的参数也就是x,就会默认使用外部变量的地址拷贝,defer是最后执行的,
在执行前y值已经被改变,defer里使用y地址取值,结果是已经改变的值。


同样的如果不是defer,使用go,闭包函数并发执行,也可能主线程的值先被改变,go出去的线程用y地址取值,y值发生变化


免责声明:文章转载自《golang闭包和range,关于闭包内使用外部变量》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇微信小程序注册开发流程centos7 配置静态ip下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C 位域

C位域如果程序的结构中包含多个开关量,只有 TRUE/FALSE 变量,如下: struct { unsigned intwidthValidated; unsigned intheightValidated; } status; 这种结构需要 8 字节的内存空间,但在实际上,在每个变量中,我们只存储 0 或 1。在这种情况下,C 语言提供了...

JS基础知识1

基础点: es5 原型链、 2. 继承、 3. this指向、 4. new操作符、 5. 隐式转换、 6. 事件循环机制macro micro、 7. 基础类型、 8. 数据去重/交集/并集、 9. 判断是否为数组、 10. 变量声明提升、 11. 函数作用域、 12. 节流/防抖、 13.  apply/call、 14.  jsonp跨域、 15....

pcntl_fork()函数说明

pcntl_fork()函数复制了当前进程的PCB,并向父进程返回了派生子进程的pid,父子进程并行,打印语句的先后完全看系统的调度算法,打印的内容控制则靠pid变量来控制。因为我们知道pcntl_fork()向父进程返回了派生子进程的pid,是个正整数;而派生子进程的pid变量并没有被改变,这一区别使得我们看到了他们的不同输出。 1. 派生子进程的进程,...

IL 汇编学习笔记(一)

今天我开始了 IL 汇编语言的学习,下面都是对一篇文章学习过程的翻译和摘要。原文:http://www.codeproject.com/dotnet/ilassembly.asp先从一个 HelloWorld 例子开始: //Test.IL//Asimpleprogrammewhichprintsastringontheconsole.assemblyex...

golang的安装后的文件目录解析

golang的安装是个比较有意思的问题首先我们要分清楚有goroot和gopath这两个环境变量。goroot是go语言安装的地方我的是在D:/go,这个不是非常重要。值得关注的是gopath,gopath一般默认安装在C:Users用户名go这个位置这里的目录结构是这样的。bin文件是存放go文件编译后的exe文件,src文件里的文件目录是这样的其中ne...

4、MySQL 申明变量给查询数据编号

摘自:   https://www.cnblogs.com/qixuejia/archive/2010/12/21/1913203.html   https://blog.csdn.net/arbben/article/details/78665389 1、mysql中变量不用事前申明,在用的时候直接用“@变量名”使用就可以了。    mysql定义用户变...