我在Scala中做了一些编程,我知道,例如,
xs map f
与
相同xs.map(f)
但我不知道如何将这种语法概括为像ScalaTest的语法,例如,
it should "throw NoSuchElementException if an empty stack is popped" in {
val emptyStack = new Stack[String]
evaluating { emptyStack.pop() } should produce [NoSuchElementException]
}
我主要想知道看起来像多字构造的东西,即should produce
。它很整洁。
答案 0 :(得分:11)
这种语法是运算符表示法中的方法调用,但不仅仅是三个令牌。如你所说:
xs map f
表示:
xs.map(f)
但你可以更进一步说:
xs map f map g
表示:
xs.map(f).map(g)
例如,在ScalaTest匹配器中,您可以说:
result should not be null
编译器对它感到害怕:
result.should(not).be(null)
此:
it should "throw an exception" in { ... }
变得卑鄙:
it.should("throw an exception").in { ... }
最后的花括号实际上只是将花括号(测试代码)之间的代码传递给in方法的一种方法,包装为无参数函数。所以这些都是同一个想法。运算符表示法连续两次使用。
你问到的最后一个有点不同:
evaluating { ... } should produce [IllegalArgumentException]
这变成了:
首先评估 evaluating { ... }
,因为花括号使它优先。这是一个方法调用,您正在调用一个名为“evaluate”的方法,将花括号之间的代码作为无参数函数传递。返回一个应该调用的对象。所以应该是通过调用求值返回的对象的方法。实际需要的是调用产品的结果。这里产生的实际上是一个方法,它有一个类型参数,如[IllegalArgumentException]
。它必须以这种方式完成,因此Scala编译器可以“穷人 - 实现”该类型参数。它将隐式“Manifest”参数传递给可以为java.lang.Class
提供IllegalArgumentException
实例的产品。因此,当调用方法时,它有一个包含传递给求值的代码的函数,以及一种查找放在方括号中的异常类型的java.lang.Class
的方法。因此它执行try中包含的代码块,捕获异常,将其与预期进行比较。如果没有抛出异常或错误的异常,则should方法抛出TestFailedException。否则,should方法只是静默返回。
所以,答案就是这条线被玷污了:
(evaluating { ... }).should(produce[IllegalArgumentException] (compilerSuppliedManifest))
故事的寓意是,像这样的高级代码使得更容易看到程序员的意图,但往往更难理解代码的实际工作方式。在实践中大部分时间你所关心的只是意图,但是你需要知道某些东西是如何工作的。在Scala中的这种情况下,您可以将-Xprint:typer作为命令行arg传递给Scala编译器,它将在所有desugaring发生后打印出您的文件版本。所以你可以在需要时看到什么。
答案 1 :(得分:2)