4

如何检查一个 Matcher 片段中的多个表达式?

例如:

class Foo extends Specification {
   "Retrieving open issues" should {
      "return expected properties with expected data" in     {
         val issue = Bar.openIssues.head

         issue must not beNull
         issue.number must beEqualTo(1) 
         issue.state must beEqualTo("open")
         issue.title must beEqualTo("first issue")
      }
   }
}

给出错误

[error]  type mismatch;
[error]  found   : Int
[error]  required: org.specs2.matcher.Matcher[Issue]
[error]                         issue.number must beEqualTo(1)

Eric 在此评论中引用了“经典”类型推理问题,但找不到答案。

4

1 回答 1

4

问题出在这一行:

issue must not beNull

因为它是用运算符表示法编写的,所以编译器必须在正确的位置推断点和括号。obj meth arg遵循与此行相同的规则obj.meth(arg)被解释为:

issue.must(not).beNull<missing_arg>

beNull是在 的返回值上调用的成员issue.must(not)。编译器遵循运算符符号的规则,并将其视为methwhileissue.must(not)被视为obj。因为运算符表示法总是要求调用必须具有形式obj meth arg,所以在上面的示例中,编译器会因为无效的语法而抛出错误。但它没有这样做,因为还有两个进一步的规则:

  1. 分隔运算符符号中标识符的空格不仅必须包含空格或制表符,还可以包含单个(!)换行符。
  2. 如果找不到arg,则隐式插入一个空参数列表。

由于 (1),编译器将下一行视为arg

issue.must(not).beNull(
issue.number).must(beEqualTo(1))

这不是代码应该被解释的方式。为了解决这个问题,可以将整个表达式括在括号中:

(issue must not beNull)

或用空行分隔行:

issue must not beNull

issue.number must beEqualTo(1)

两种解决方案都有效,因为 (2) 编译器可以插入一个空参数列表。

注意:如果必须应用 (2),这也称为后缀运算符。在 2.10 中,他们处理警告是因为——正如从这个问题中可以看到的——它们可能导致棘手的行为。

于 2013-01-15T13:09:49.370 回答