【发布时间】:2016-07-21 09:17:21
【问题描述】:
闭包中不允许有可变值,但for .. in 表达式是可以的。在 C# 中,for 循环会更新迭代器,但在 F# 中似乎没有。如何以及为什么?
【问题讨论】:
标签: for-loop foreach f# closures immutability
闭包中不允许有可变值,但for .. in 表达式是可以的。在 C# 中,for 循环会更新迭代器,但在 F# 中似乎没有。如何以及为什么?
【问题讨论】:
标签: for-loop foreach f# closures immutability
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 在闭包中,因为它实际上并没有改变任何东西。
【讨论】: