F#"做"语句为块表达式

时间:2018-02-24 12:32:37

标签: f# dispose

F# spec在模块中的 10.2.5 do语句中描述,在模块级别上do语句可能具有属性,并且它将生成当表达式的类型未计算为unit时的警告。显然,do语句在其他位置的行为类似于Block表达式( 6.5.1 ),无论是括号还是开始结束,同时仍然断言{ {1}}输入。

这使得unit语句适合控制确定性处置表达式的范围( 6.6.4 ):

do

如果规范中没有明确说明,还有什么能阻止F#编译器的维护人员破坏这种用法吗?

2 个答案:

答案 0 :(得分:2)

我认为示例中的aba函数实际上同时使用了do语句和块表达式。 do的语法是do <expr>,因此do语句的主体是单个表达式。如果我们用括号写相同的东西:

let aba() =
  use a = d "a"
  do ( use b = d "b"
       printf "a + b, " )
  printf "a, "

确定性处置行为然后来自块表达式的通常确定性处置行为 - 而不是来自do块的一些未记录的属性。

答案 1 :(得分:0)

这里根本不需要do语句,使用括号就足够了:

let aba() =
    use a = d "a"
    (
        use b = d "b"
        printf "a + b, "
    )
    printf "a, "
aba(); printfn ""
// Prints "new a, new b, a + b, disposing b, a, disposing a, "

这是Tomas Petricek的例子减去do。括号为它们包含的代码块定义了一个新范围,因此当您到达右括号时,b超出范围并被处置。为了证明范围规则是这样的,让我们添加另一个变量定义:

let aba() =
    use a = d "a"
    (
        use b = d "b"
        let c = 5
        printf "a + b, and c=%d " c  // This compiles
    )
    printf "and now c=%d " c  // This does not compile
    printf "a, "
aba(); printfn ""

括号内的c的第一次使用将被编译。括号外的c的第二次使用将无法编译,因为此时c超出了范围,您将获得:

  

错误FS0039:未定义值或构造函数“c”。

因此,如果您正在使用do表达式来控制IDisposable何时超出范围,则可以仅使用括号来实现相同的结果。由您决定哪种形式更具可读性。