为什么 '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
在闭包中,因为它 实际上没有改变任何东西。
闭包中不允许使用可变值,但 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
在闭包中,因为它 实际上没有改变任何东西。