在 Scala 中从抽象 class 创建匿名 class - 脱糖代码

Creating an anonymous class from an abstract class in Scala - desugaring code

这里是 Scala 菜鸟。

我不理解以下摘自 Play 应用程序集成测试 (Scala) 的代码:

package workflows.admin

import play.api.test._

class SignInSpec extends PlaySpecification {

  "An activated user" should {
    "be able to sign in to the admin console" in new WithBrowser(webDriver = WebDriverFactory(FIREFOX)) {
      // some matchers here ...
      true
    }
  }
}

据我了解,该示例从抽象 class WithBrowser 创建了一个新的匿名 class 并将其实例化。该实例将接收(命名的)构造函数参数 webDriver.

问题是我在查看 WithBrowser:

时不明白这里发生了什么
abstract class WithBrowser[WEBDRIVER <: WebDriver](
    val webDriver: WebDriver = WebDriverFactory(Helpers.HTMLUNIT),
    val app: Application = GuiceApplicationBuilder().build(),
    val port: Int = Helpers.testServerPort) extends Around with Scope {

  def this(
    webDriver: Class[WEBDRIVER],
    app: Application,
    port: Int) = this(WebDriverFactory(webDriver), app, port)

  implicit def implicitApp: Application = app
  implicit def implicitPort: Port = port

  lazy val browser: TestBrowser = TestBrowser(webDriver, Some("http://localhost:" + port))

  override def around[T: AsResult](t: => T): Result = {
    try {
      Helpers.running(TestServer(port, app))(AsResult.effectively(t))
    } finally {
      browser.quit()
    }
  }
}

我有两个问题:

  1. WithBrowser 是带有类型参数 WEBDRIVER 的泛型抽象 class,但示例中未声明类型参数。相反,匿名 class' 实例使用命名的构造函数参数 webDriver 接收此信息。类型参数和构造函数参数之间缺少什么link?
  2. 该示例声明了一个代码块(它只是 returns true),这个代码块就是测试本身。但是该代码在匿名 class 中放在哪里? WithBrowser 扩展了 Around 并覆盖了执行代码块的 around 函数,但我不明白生成的匿名 class 如何将给定的示例代码块移动到 around.

非常感谢任何帮助。

  1. Scala 可以推断类型参数。由于传递参数类型的 none 在某种程度上与类型参数相关,因此会限制要推断的类型,因此 Scala 编译器只会将其推断为类型 Nothing.

  2. 代码块通常是class的构造函数,但这是一个特例。 Around class 确实扩展了 scala.DelayedInit 接口。这会将构造函数中的代码重写为 delayedInit 函数的调用。实际上是构造函数的代码作为按名称调用的参数传递给此函数。这个值(实际上包含在 org.specs2.execute.Result.resultOrSuccess 调用中)是传递给 around 函数的参数。

想象一下 Around class 是这样的:

class Around extends DelayedInit {
  def delayedInit(f: => Unit): Unit = around(f)
  def around(f: => Unit): Unit
}

假设您现在将继承 class:

class Foo extends Around {
  println("Hello World")
}

上面被重写为:

class Foo extends Around {
  delayedInit(println("Hello World"))
}

如果我的解释不够清楚或者您想了解更多实现细节:
- 这是 Around and the DelayedInit 文档。