为什么 'for .. in' 允许在闭包中?

Why 'for .. in' allowed in closures?

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

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()

如果 txt 每次通过 for .. in 循环都是同一个变量,这将打印 ghi ghi ghi,就像 C# 4 和更早版本一样——因为匿名函数关闭在变量上,在循环之后变量包含 ghi。但是如果你 运行 上面的代码,你会看到它打印 abc def ghi,就像 C# 5 和更高版本一样。

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