C# foreach语法糖背后的秘密:闭包与迭代变量的那些事
创作时间:
作者:
@小白创作中心
C# foreach语法糖背后的秘密:闭包与迭代变量的那些事
引用
1
来源
1.
https://cloud.tencent.com/developer/article/2196843
本文通过对比C#中的for循环和foreach循环在闭包处理上的差异,深入探讨了为什么foreach能够正确输出迭代值,而for循环则不能。文章还进一步扩展到Go语言的for循环陷阱,并提供了相应的解决方案。
让我们先来看一个C#的示例代码:
var t1 = new List<Action>();
for (int i = 0; i < 5; i++)
{
var func = (() =>
{
Console.WriteLine(i);
});
t1.Add(func);
}
foreach (var item in t1)
{
item();
}
左边输出5个5;右边输出0,1,2,3,4。
闭包原理
闭包是在词法环境中捕获自由变量的头等函数。在上述代码中,关键在于闭包捕获的自由变量。
这里有三个关键概念需要理解:
- 局部变量i是被头等函数引用的自由变量
- 闭包捕获变量i的时空和闭包执行的时空不是一个时空
- 所有闭包执行时,捕获的都是变量i的最终值
解决方案
为了应对这种陷阱,可以在循环内使用一个局部变量来解构每个闭包与全局自由变量i的关系:
var t1 = new List<Action>();
for (int i = 0; i < 5; i++)
{
var j = i;
var func = (() =>
{
Console.WriteLine(j);
});
t1.Add(func);
}
foreach (var item in t1)
{
item();
}
foreach的底层实现
foreach的底层实现依赖于IEnumerable和IEnumerator两个接口。下面是foreach的伪代码:
{
E e = ((C)(x)).GetEnumerator();
try
{
while (e.MoveNext())
{
V v = (V)(T)e.Current; // 注意,变量v的定义是在循环体内
/*embedded_statement*/
}
}
finally
{
... // Dispose e
}
}
由于变量v的定义在while循环内部,因此使用foreach迭代时,每个闭包捕获的都是局部的自由变量,因此foreach闭包执行能输出0,1,2,3,4。
Golang的for循环陷阱
Golang中只有for循环,没有while和foreach关键字。下面是一个示例:
package main
import "fmt"
var slice []func()
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()
}
}
输出结果:
0xc00001c098 1
0xc00001c098 2
0xc00001c098 3
0xc00001c098 4
0xc00001c098 5
5
5
5
5
5
Golang的for-range循环本质上与C#的for循环相同,闭包引用的是全局的自由变量v。解决方法是在循环体内创建局部变量:
for _, v := range sli {
v := v
fmt.Println(&v, v)
slice = append(slice, func() {
fmt.Println(v)
})
}
总结
本文主要讨论了以下几个知识点:
- 闭包:是在词法环境中捕获自由变量的头等函数
- foreach语法糖:依赖于IEnumerable和IEnumerator接口实现,同时foreach每次迭代使用的是块内局部变量
- for循环变量是相对的全局变量,这也是导致闭包陷阱的原因
这些知识点都很重要且较为晦涩,建议读者关注文中给出的参考资料,以便进一步学习和探讨。
参考资料
热门推荐
小儿止咳糖浆乱用会产生那些危害呢
过保商品维修遇阻?这些维权途径帮你讨回"被消费"的钱包
王升启团队揭秘志愿军遗骸身份确认黑科技
第十一批志愿军遗骸归国,青年如何传承英雄精神?
向药物滥用说不!“止咳神药”右美沙芬监管升级了
如何鉴别正宗汾酒黑坛20年和青花30年
古井亭商标揭秘:教你识破假汾酒
智能技术优化电动车充电:降本增效,绿色节能
七成飞蚊症无需过度担忧,中西医结合助力科学防治
以身作则,勇闯职场:如何通过领导力培训激发团队潜能
氨碘肽滴眼液使用全指南:功效、禁忌与患者体验
氨碘肽滴眼液治疗飞蚊症效果显著,但需遵医嘱使用
感恩与奋斗:职场逆袭秘籍
高效时间管理,职场逆袭秘籍
职场伪人:揭秘他们的心理秘密
职场“伪人”现象:虚伪行为的心理剖析与应对之道
冬游奇台古城:赏雪、泡温泉、品美食一站式指南
新疆唐朝墩古城:发现世界最完整景教壁画的多元文化中心
冬游新疆奇台:江布拉克1元门票等你抢,还有酒文化博物馆免费开放
远离人品不佳的朋友:8种需要警惕的特征
黑暗人格全解析:特征、最新研究与应对方法
当心背后刀:8个特征识别“有毒”朋友,5个方法保护自己
气血不通?中医教你快速调理
西安市某高校防诈秘籍大揭秘:构建校园反诈防线
双十二后,大学生防诈骗攻略
社交媒体文案如何突破转发瓶颈?六大实操技巧详解
斯坦福科学家:如何有效提升动力、专注力与满足感
中国养老性价比最高的四座沿海城市,环境好消费低,你会选哪一个
广西北海属于什么气候
中年男人的养生指南:科学饮食、规律运动和心理健康一个都不能少