视频网站开发计划书,河北秦皇岛黄金海岸,湛江建设企业网站,上海网站建设__永灿品牌建站本文的知识点其实由golang知名的for循环陷阱发散而来#xff0c; 对应到我的主力语言C##xff0c; 其实牵涉到闭包、foreach。为了便于理解#xff0c;我重新组织了语言#xff0c;以倒叙结构行文。先给大家提炼出一个C#题#xff1a;观察for、foreach闭包的差异左边输出… 本文的知识点其实由golang知名的for循环陷阱发散而来 对应到我的主力语言C# 其实牵涉到闭包、foreach。为了便于理解我重新组织了语言以倒叙结构行文。先给大家提炼出一个C#题观察for、foreach闭包的差异左边输出 5个5右边输出0,1,2,3,4 答对的、不屑看题的同学都可以出门右转了。闭包是在词法环境中捕获自由变量的头等函数 题中关键是捕获的自由变量。这里面有3个关键名词希望大家重视可以围观我之前的 新来的总监把C#闭包讲得那叫一个透彻[1]。demo1for循环内闭包局部变量i是被头等函数引用的自由变量相对于每个头等函数i是全局变量闭包捕获变量i的时空和 闭包执行的时空不是一个时空所有闭包执行时捕获的都是变量i所以执行输出的都是i最后的5。这也是C#闭包的陷阱 通常应对方式是循环内使用一个局部变量解构每个闭包与(相对全局)变量i的关系。var t1 new ListAction();for (int i 0; i 5; i){// 使用局部变量解绑闭包与全局自由变量i的关系,现在自由变量是局部变量j了。var j i;var func (() {Console.WriteLine(j);});t1.Add(func);}foreach (var item in t1){item();}demo2foreach内闭包为什么能输出预期的0,1,2,3,4。聪明的读者可以猜想是不是foreach在循环迭代时 给我们搞出了局部变量j帮我们解构了闭包与全局自由变量i多对1的关系。foreach的底层实现有赖于IEnumerable和IEnumerator两个接口的实现、这里也有一个永久更新的原创文IEnumerator、IEnumerable还傻傻分不清楚[2]但是怎么用这个两个接口还需要看foreach伪代码 C# foreach foreach (V v in x) «embedded_statement»被翻译成下面代码{E e ((C)(x)).GetEnumerator();try{while (e.MoveNext()){V v (V)(T)e.Current; // 注意 变量v的定义是在循环体内«embedded_statement»}}finally{... // Dispose e}
}foreach官方信源[3]请注意注释变量v的定义是在while循环内部 因此使用foreach迭代时每个闭包捕获的都是局部的自由变量 因此foreach闭包执行能输出0,1,2,3,4。如果变量V v定义在while语言上方那么效果就和for循环一样了。这是for循环/foreach迭代一个很有意思的差异。再来看看引发我思考的Golang的for循环陷阱 Golang只有for循环没有whileforeach关键字。 package mainimport fmtvar slice []func()
//for循环产生闭包切片
func main() {sli : []int{1, 2, 3, 4, 5}for _, v : range sli {fmt.Println(v, v)slice append(slice, func() {fmt.Println(v) })}for _, val : range slice {val()}
}
--- output ---
0xc00001c098 1
0xc00001c098 2
0xc00001c098 3
0xc00001c098 4
0xc00001c098 5
5
5
5
5
5golang for循环作用在切片上使用姿势类似于C#的 foreach但是内核却是c# for循环。每个闭包引用的都是(相对全局的)自由变量v最终闭包拿到的是一个变量的最终值。应对这种陷阱的思路依旧是使用循环内局部变量去解构闭包与(相对全局)z自由变量v的关系。画外音本文其实内容很多闭包是在词法环境中捕获自由变量的头等函数foreach 语法糖依赖于IEnumerable和IEnumerator 接口实现同时 foreach每次迭代使用的是块内局部变量 for循环变量是相对的全局变量 也正是这个差异导致了投票题的结果。每一个知识点都是重要且晦涩篇幅有限请适时关注文中给出的几个永久更新地址也请各大佬斧正协助我永久更新☺️☺️。参考资料[1]新来的总监把C#闭包讲得那叫一个透彻: https://www.cnblogs.com/JulianHuang/p/14618378.html[2]IEnumerator、IEnumerable还傻傻分不清楚: https://www.cnblogs.com/JulianHuang/p/14271285.html[3] foreach官方信源: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/statements#1295-the-foreach-statement