go词法作用域陷进
问题
// 创建一些目录,再将目录删除
// 错误写法
var rmdirs []func()
for _, dir := range tempDirs() {
os.MkdirAll(dir, 0755)
rmdirs = append(rmdirs, func(){
os.RemoveAll(dir)
})
}
// 正确写法
var rmdirs []func()
for _, d := range tempDirs() {
dir := d // 这一步赋值比较关键,是重点
os.MkdirAll(dir, 0755)
rmdirs = append(rmdirs, func() {
os.RemoveAll(dir)
})
}
for _, rmdir := range rmdirs{
rmdir()
}
分析
你可能会感到困惑,为什么要在循环体中用循环变量d赋值一个新的局部变量,而不是直接使用循环变量dir
问题的原因在于循环变量的作用域。在上面的程序中,for循环语句引入了新的词法块,
循环变量dir在这个词法块中被声明。在该循环中生成的所有函数值都共享相同的循环变量。
需要注意,函数值中记录的是循环变量的内存地址,而不是循环变量某一个时刻的值。以dir为例
后续的迭代会不断更新dir的值,当删除操作执行时,for循环已完成,dir中存储的值
等于最后一次迭代的值。这意味着,每次对os.RemoveAll的调用删除的都是相同的目录
通常,为了解决这个问题,我们会引入一个与循环变量同名的局部变量,作为循环变量
的副本。比如下面的变量dir,虽然看起来很怪,但很有用
for _, dir := range tempDirs(){
dir := dir
}
当然这个问题不仅存在基于range循环,下面的例子中,对循环变量i的使用也存在同样的问题
var rmdirs []func()
dirs := tempDirs()
for i := 0;i<len(dirs);i++{
os.MkdirAll(dirs[i], 0755)
rmdirs = append(rmdirs, func(){
os.RemoveAll(dirs[i])
})
}
如果你使用go语句或者defer语句会经常遇到此类问题。这不是go或defer本身导致的,
而是因为它们都会等待循环结束后,再执行函数值。
go词法作用域陷进的更多相关文章
- JavaScript夯实基础系列(一):词法作用域
作用域是一组规则,规定了引擎如何通过标识符名称来查询一个变量.作用域模型有两种:词法作用域和动态作用域.词法作用域是在编写时就已经确定的:通过阅读包含变量定义的数行源码就能知道变量的作用域.Jav ...
- Javascript中的词法作用域、动态作用域、函数作用域和块作用域(四)
一.js中的词法作用域和动态作用域 词法作用域也就是在词法阶段定义的作用域,也就是说词法作用域在代码书写时就已经确定了. js中其实只有词法作用域,并没有动态作用域,this的执 ...
- 你不知道的Javascript(上卷)读书笔记之二 ---- 词法作用域
在前一篇文章中,我们把作用域定义为"管理.维护变量的一套规则",接下来是时候来深入讨论一下Js的作用域问题了,首先我们要知道作用域一般有两种主要的工作类型,一种是词法作用域,一种是 ...
- Coursera系列-R Programming第三周-词法作用域
完成R Programming第三周 这周作业有点绕,更多地是通过一个缓存逆矩阵的案例,向我们示范[词法作用域 Lexical Scopping]的功效.但是作业里给出的函数有点绕口,花费了我们蛮多心 ...
- JavaScript闭包之“词法作用域”
大家应该写过下面类似的代码吧,其实这里我想要表达的是有时候一个方法定义的地方和使用的地方会相隔十万八千里,那方法执行时,它能访问哪些变量,不能访问哪些变量,这个怎么判断呢?这个就是我们这次需要分析的问 ...
- 深入理解javascript作用域系列第二篇——词法作用域和动态作用域
× 目录 [1]词法 [2]动态 前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极 ...
- JavaScript 使用词法作用域,没有动态作用域
function foo() { console.log( a ); } function bar() { var a = 3; foo(); } var a = 2; bar(); 上面的代码,控制 ...
- JavaScript高级之词法作用域和作用域链
主要内容: 分析JavaScript的词法作用域的含义 解析变量的作用域链 变量名提升时什么 一.关于块级作用域 说到JavaScript的变量作用域,与咱们平时使用的类C语言不同. ...
- 《你不知道的JavaScript》读书笔记(二)词法作用域
JavaScript 采用的是 词法作用域 的工作模型. 定义 词法化:大部分标准语言编译器的第一个工作阶段叫词法化(单词化),这个过程会对源代码中的字符进行检查,如果是有状态的解析过程,还会赋予单词 ...
- js词法作用域规则
function foo() {console.log( a ); // 2不是3} function bar() {var a = 3;foo();} var a = 2;bar(); js中的作用 ...
随机推荐
- [转帖] Linux查看日志文件写入速度的4种方法
https://www.cnblogs.com/codelogs/p/16365448.html 简介# 有时,我们需要查看某个文件的增长速度,如日志文件,以此来感受系统的负载情况,因为一般情况下,日 ...
- RabbitMQ 测试环境的简单创建于使用 permission vhost 以及 权限简单设置
之前用docker运行起来 rabbitmq的容器了 但是今天发现有问题. 简单沟通了下 需要进行处理. 方法主要是如下 1. 运行容器: docker run --name rabbitmq -ti ...
- K8S 使用loki 监控 应用日志的搭建办法
1. 背景 这几天一直在用k8s部署分SU的测试环境,开发反馈看日志比较麻烦. 昨天晚上在家里本来想搭建ELK 发现比较重, 又说有一个比较轻量级的 loki 可以实现使用grafana进行监控和查看 ...
- Ant Design Vue分页Pagination
<template> <div> <a-pagination show-quick-jumper v-model:current="current1" ...
- AspnetCore接入Nacos配置中心
一.什么是nacos Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现.配置管理 ...
- 8.5 C++ 继承与多态
C/C++语言是一种通用的编程语言,具有高效.灵活和可移植等特点.C语言主要用于系统编程,如操作系统.编译器.数据库等:C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统.图形用户界面 ...
- LyScript 批量搜索反汇编特征
LyScript 插件实现对特定汇编指令片段的批量搜索功能,用户传入一个汇编指令列表,然后循环搜索该列表内的所有指令特征,如果找到了,则返回该指令的内存地址. 插件地址:https://github. ...
- 教你用JavaScript实现实时字符计数器
案例介绍 欢迎来到我的小院,我是霍大侠,恭喜你今天又要进步一点点了!我们来用JavaScript编程实战案例,做一个实时字符计数器.用户在指定位置打字,程序实时显示字符数量. 案例演示 在编辑框内输入 ...
- CH9140,CH9141,CH9143异同点
9140:是一款蓝牙转串口芯片,芯片支持蓝牙主从一体模式或从机模式,支持蓝牙 BLE4.2.串口波特率最高 1Mbps,支持 MODEM 联络信号,蓝牙主从模式可以自动连接或绑定. 智能配对功能 当 ...
- WebAssembly核心编程[4]: Memory
由于Memory存储的是单纯的二进制字节,所以原则上我们可以用来它作为媒介,在wasm模块和数组程序之间传递任何类型的数据.在JavaScript API中,Memory通过WebAssembly.M ...