Scala:带有/不带()的方法的调用带有可覆盖的含义

Ale*_*ndr 0 overriding scala implicit

这是方法的定义,它ExecutionContext隐式使用,并允许客户端覆盖它.两个执行上下文用于测试它:

val defaultEc = ExecutionContext.fromExecutor(
    Executors.newFixedThreadPool(5))
Run Code Online (Sandbox Code Playgroud)

线程名称如下所示:'pool-1-thread-1'到'pool-1-thread-5'

而斯卡拉的第二个:

scala.concurrent.ExecutionContext.Implicits.global
Run Code Online (Sandbox Code Playgroud)

线程名称如下所示:'scala-execution-context-global-11'

客户端可以覆盖默认隐式通过:

implicit val newEc = scala.concurrent.ExecutionContext.Implicits.global
Run Code Online (Sandbox Code Playgroud)

不幸的是,只有在没有调用带隐式的方法时,它才可以覆盖():

val r = FutureClient.f("testDefault") //prints scala-execution-context-global-11
Run Code Online (Sandbox Code Playgroud)

不工作:

val r = FutureClient.f("testDefault")() //still prints: pool-1-thread-1
Run Code Online (Sandbox Code Playgroud)

问题是为什么它以这种方式工作?因为它使API的客户端变得更加复杂

以下是运行和播放的完整代码:

object FutureClient {
  //thread names will be from 'pool-1-thread-1' to 'pool-1-thread-5'
  val defaultEc = ExecutionContext.fromExecutor(
    Executors.newFixedThreadPool(5))

  def f(beans: String)
           (implicit executor:ExecutionContext = defaultEc)
  : Future[String] = Future {
    println("thread: " + Thread.currentThread().getName)
    TimeUnit.SECONDS.sleep(Random.nextInt(3))
    s"$beans"
  }
}

class FutureTest {
  //prints thread: pool-1-thread-1
  @Test def testFDefault(): Unit ={
    val r = FutureClient.f("testDefault")
    while (!r.isCompleted) {
      TimeUnit.SECONDS.sleep(2)
    }
  }

  //thread: scala-execution-context-global-11
  @Test def testFOverridable(): Unit ={
    implicit val newEc = scala.concurrent.ExecutionContext.Implicits.global
    val r = FutureClient.f("testDefault")
    while (!r.isCompleted) {
      TimeUnit.SECONDS.sleep(2)
    }
  }

  //prints pool-1-thread-1, but not 'scala-execution-context-global-11'
  //cause the client invokes f with () at the end
  @Test def testFOverridableWrong(): Unit ={
    implicit val newEc = scala.concurrent.ExecutionContext.Implicits.global
    val r = FutureClient.f("testDefault")()
    while (!r.isCompleted) {
      TimeUnit.SECONDS.sleep(2)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我已经讨论过几个相关的主题,但它们与API定义有关,所以这是一个新问题,不是那些主题所涵盖的.

Dmy*_*tin 5

要避免的Scala模式:具有默认值的隐式参数

f("testDefault")(或f("testDefault")(implicitly))表示隐式参数取自隐式上下文.

f("testDefault")(newEc)表示您明确指定隐式参数.如果您这样写,f("testDefault")()则意味着您明确指定隐式参数,但由于未提供该值,因此应从默认值中获取.