2

我正在使用 FsUnit 在 F# 中编写一些单元测试,我注意到属性和类型成员中的 let 语句有一些奇怪的行为,并且想知道是否有人可以解释它?

如果我写这样的测试:

[<Fact>] member test.
  ``Test that something works correctly`` () =

    let x = 1

    x + 2 |> should equal 3

我将在 Visual Studio 2012 中的“x + 2”行的第一个字符上收到错误消息:

表达式中出现意外的关键字“让”或“使用”。预期为“in”或其他标记。

使用 'let ... in' 可以解决这个错误,但如果你想使用多个,让它很快变得混乱:

[<Fact>] member test.
  ``Test that something works correctly`` () =
    let x = 1
    in x + 2 |> should equal 3

我最终发现将属性放在单独的行上也可以解决错误:

[<Fact>]
member test.
  ``Test that something works correctly`` () =

    let x = 1

    x + 2 |> should equal 3

谁能提供任何关于为什么第一个代码片段导致错误但其他两个没有的见解?

4

2 回答 2

5

在第一个片段中,您实际上有两个缩进错误。第一个问题是''Test that something works correctly''应该在member关键字之后缩进。第二个是函数的主体应该在所有成员定义行之后缩进。

如果您修复第一个错误:

[<Fact>] member test.
           ``Test that something works correctly`` () =
    let x = 1
    x + 2 |> should equal 3

编译器将发出“可能不正确的缩进”警告,您可以通过进一步缩进函数体来解决此问题:

[<Fact>] member test.
           ``Test that something works correctly`` () =
             let x = 1
             x + 2 |> should equal 3

在第二个片段中,in关键字的使用触发了冗长的语法,其中缩进不再重要。在最后一个例子中,member恰好有最低的缩进;你顺便有正确的缩进。

也就是说,您应该避免将成员定义分成多行。在大多数情况下,您可以只使用let绑定而不是更详细的member绑定。

[<Fact>]
let ``Test that something works correctly``() =
    let x = 1
    x + 2 |> should equal 3
于 2013-05-10T14:51:16.377 回答
3

如评论中所述,您可以将属性放在 afterlet或 after member。这样,您可以将注释和成员定义放在一行中:

let [<Fact>] ``Test that something works correctly``() =
   let x = 1
   x + 2 |> should equal 3

还有一种情况是您实际上需要使用这种语法。如果您有多个相互递归的函数(可能相互调用),那么您需要使用定义它们let rec ... and,在这种情况下,您必须将属性放在后面and

let rec [<Test>] a () = 10
and [<Test>] b () = 10

但以下不是有效的语法:

[<Test>] 
let rec a () = 10
[<Test>] 
and b () = 10
于 2013-05-10T20:47:30.423 回答