Scala:调用方法 with/without () 具有可重写的隐式
Scala: Invokation of methods with/without () with overridable implicits
这里是方法的定义,它隐含地使用了ExecutionContext
,并允许客户端覆盖它。使用两个执行上下文对其进行测试:
val defaultEc = ExecutionContext.fromExecutor(
Executors.newFixedThreadPool(5))
线程名称如下:'pool-1-thread-1' 到 'pool-1-thread-5'
第二个来自 Scala:
scala.concurrent.ExecutionContext.Implicits.global
线程名称如下:'scala-execution-context-global-11'
客户端可以通过以下方式覆盖默认隐式:
implicit val newEc = scala.concurrent.ExecutionContext.Implicits.global
不幸的是,只有在没有 ()
的情况下调用具有隐式的方法时,它才可以重写:
val r = FutureClient.f("testDefault") //prints scala-execution-context-global-11
不工作:
val r = FutureClient.f("testDefault")() //still prints: pool-1-thread-1
问题是为什么它以这种方式工作?因为它使 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)
}
}
}
我已经讨论了几个相关主题,但它们与 API 定义相关,因此这是一个新问题,未包含在这些主题中。
Scala Patterns To Avoid: Implicit Arguments With Default Values
f("testDefault")
(或f("testDefault")(implicitly)
)表示隐式参数取自隐式上下文。
f("testDefault")(newEc)
表示您明确指定隐式参数。如果您写 f("testDefault")()
这意味着您显式指定了隐式参数,但由于未提供该值,因此应从默认值中获取。
这里是方法的定义,它隐含地使用了ExecutionContext
,并允许客户端覆盖它。使用两个执行上下文对其进行测试:
val defaultEc = ExecutionContext.fromExecutor(
Executors.newFixedThreadPool(5))
线程名称如下:'pool-1-thread-1' 到 'pool-1-thread-5'
第二个来自 Scala:
scala.concurrent.ExecutionContext.Implicits.global
线程名称如下:'scala-execution-context-global-11'
客户端可以通过以下方式覆盖默认隐式:
implicit val newEc = scala.concurrent.ExecutionContext.Implicits.global
不幸的是,只有在没有 ()
的情况下调用具有隐式的方法时,它才可以重写:
val r = FutureClient.f("testDefault") //prints scala-execution-context-global-11
不工作:
val r = FutureClient.f("testDefault")() //still prints: pool-1-thread-1
问题是为什么它以这种方式工作?因为它使 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)
}
}
}
我已经讨论了几个相关主题,但它们与 API 定义相关,因此这是一个新问题,未包含在这些主题中。
Scala Patterns To Avoid: Implicit Arguments With Default Values
f("testDefault")
(或f("testDefault")(implicitly)
)表示隐式参数取自隐式上下文。
f("testDefault")(newEc)
表示您明确指定隐式参数。如果您写 f("testDefault")()
这意味着您显式指定了隐式参数,但由于未提供该值,因此应从默认值中获取。