为什么在闭包中允许使用'for...in'语句?

4

闭包中不允许可变值,但for .. in表达式是可以的。在C#中,for循环更新迭代器,但似乎F#并不是这样。如何以及为什么呢?

1个回答

14

F#的for .. in相当于C#的foreach循环,而不是C#的for循环。自C# 5以来,foreach循环不会更新迭代器;它会为循环中的每次迭代创建一个新变量(这对闭包有重要影响,请参见Foreach now captures variables!(Access to modified closure)了解详细信息)。这也是F#的做法:如果你写下

for txt in ["abc"; "def"; "ghi"] do
    printfn "%s" txt

如果你运行那个循环,实际上会创建三个新的字符串变量,而不仅仅是一个。

为了证明F#每次都会创建一个新变量,请尝试以下不太函数化的代码:

let actions = new System.Collections.Generic.List<System.Action<unit>>()
for txt in ["abc"; "def"; "ghi"] do
    actions.Add(fun () -> printf "%s " txt)
for action in actions do
    action.Invoke()

如果在for.. in循环中每次使用的是同一个变量txt,那么它将打印ghi ghi ghi,就像C# 4及更早版本一样 -- 因为匿名函数关闭了变量,并且在循环后,变量包含ghi。但是如果运行上面的代码,你会发现它打印abc def ghi,就像C# 5及更高版本一样。

所以回答您的问题是,F#允许在闭包中使用for .. in,因为它实际上没有改变任何东西


1
非常好的答案,谢谢。 - aikixd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接