隐藏页面特效

go词法作用域陷进

1|0问题


// 创建一些目录,再将目录删除 // 错误写法 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() }

2|0分析


你可能会感到困惑,为什么要在循环体中用循环变量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语句会经常遇到此类问题。这不是godefer本身导致的, 而是因为它们都会等待循环结束后,再执行函数值。

__EOF__

本文作者404 Not Found
本文链接https://www.cnblogs.com/weiweivip666/p/15937193.html
关于博主:可能又在睡觉
版权声明:转载请注明出处
声援博主:如果看到我睡觉请喊我去学习
posted @   我在路上回头看  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示