【问题标题】:Why 'for .. in' allowed in closures?为什么在闭包中允许“for .. in”?
【发布时间】:2016-07-21 09:17:21
【问题描述】:

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

【问题讨论】:

    标签: for-loop foreach f# closures immutability


    【解决方案1】:

    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 在闭包中,因为它实际上并没有改变任何东西

    【讨论】:

    • 很好的答案,谢谢。
    猜你喜欢
    • 1970-01-01
    • 2018-01-16
    • 2014-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 1970-01-01
    • 2014-02-19
    相关资源
    最近更新 更多