闭包中不允许可变值,但for .. in
表达式是可以的。在C#中,for循环更新迭代器,但似乎F#并不是这样。如何以及为什么呢?
闭包中不允许可变值,但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()
如果在for.. in
循环中每次使用的是同一个变量txt
,那么它将打印ghi ghi ghi
,就像C# 4及更早版本一样 -- 因为匿名函数关闭了变量,并且在循环后,变量包含ghi
。但是如果运行上面的代码,你会发现它打印abc def ghi
,就像C# 5及更高版本一样。
所以回答您的问题是,F#允许在闭包中使用for .. in
,因为它实际上没有改变任何东西。