我已经尝试了How to override an implicit value?中所述的解决方案,但无济于事。这是一个代码示例。
具有2种不同实现的TestImplicit抽象定义(类似ExecutionContextExecutor
):
trait TestImplicit {
def f(s:String):Unit
}
object TestImplicitImpl1 extends TestImplicit {
override def f(s: String): Unit = println(s"1: $s")
}
object TestImplicitImpl2 extends TestImplicit {
override def f(s: String): Unit = println(s"2: $s")
}
在ImplDefinition
对象中,定义了一个q
变量,以通过import(与ExecutionContext.Implicits.global
的类似物)隐式使用:
object ImplDefinition {
implicit val q:TestImplicit = TestImplicitImpl1
}
定义方法的客户端,它隐式接受TestImplicit
(类似于scala.concurrent.Future):
trait TestImplicitClient {
def fu(implicit ti:TestImplicit):Unit
}
object TestImplicitClient extends TestImplicitClient {
override def fu(implicit ti: TestImplicit): Unit = {
println("client")
ti.f("param")
}
}
下一步是选择要使用TestImplicit
的实现的客户端客户,通过import
(使用Future
的API的模拟)来做出决定:< / p>
object ClientOfClient {
import somepackage.ImplDefinition.q
def t():Unit =
TestImplicitClient.fu
}
现在在测试中,我想使用此ClientOfClient.t()
,但是我需要覆盖隐式,而改用TestImplicitImpl2
。背后的主要思想-隐式应该由API的客户端定义/重写,而不是由API本身定义:
import somepackage.{ClientOfClient, TestImplicit, TestImplicitImpl2}
import org.junit.Test
class ImplTest {
// trying to hide it via import, does not help
import somepackage.ImplDefinition.{q => _,_}
@Test def test(): Unit ={
//trying to hide it via downgrading to non-implicit, does not work either
val q = somepackage.ImplDefinition.q
implicit val ti = TestImplicitImpl2
ClientOfClient.t()
}
}
每次运行测试时,我都会得到输出:
client
1: param
但没想到:
client
2: param
我该如何解决?我需要一种允许客户端重写隐式并使用尽可能简单的API的方法。这意味着,我不想在ClientOfClient.t()
方法中添加其他隐式参数。
答案 0 :(得分:1)
一旦到处都有一个带有硬编码常量ClientOfClient
的单例对象TestImplicitImpl1
,实际上您将无能为力。但是有几种解决方法。
object ClientOfClient {
def t()(implicit ti: TestImplicit = ImplDefinition.q): Unit =
TestImplicitClient.fu
}
object ImplTest {
def test(): Unit = {
implicit val ti2 = TestImplicitImpl2
ClientOfClient.t()
}
}
ImplTest.test() // 2: param
如果要使隐式重写可覆盖,则使ClientOfClient
可扩展,并创建一个返回隐式方法的方法(此处为“ cocti
”),而不是import
直。然后,您可以覆盖该方法(而您不能覆盖导入)。
这将在一天结束时产生2: param
:
trait TestImplicit {
def f(s: String): Unit
}
object TestImplicitImpl1 extends TestImplicit {
override def f(s: String): Unit = println(s"1: $s")
}
object TestImplicitImpl2 extends TestImplicit {
override def f(s: String): Unit = println(s"2: $s")
}
object ImplDefinition {
implicit val q: TestImplicit = TestImplicitImpl1
}
trait TestImplicitClient {
def fu(implicit ti: TestImplicit): Unit
}
object TestImplicitClient extends TestImplicitClient {
override def fu(implicit ti: TestImplicit): Unit = {
println("client")
ti.f("param")
}
}
class ClientOfClient {
implicit def cocti: TestImplicit = {
ImplDefinition.q
}
def t():Unit =
TestImplicitClient.fu
}
object ImplTest {
def test(): Unit = {
implicit val ti2 = TestImplicitImpl2
new ClientOfClient {
override def cocti = ti2
}.t()
}
}
ImplTest.test() // 2: param