【发布时间】:2015-12-21 08:33:49
【问题描述】:
我有以下问题,这可能是最好的例子:
1) 此代码在库中提供
sealed trait Base
class A extends Base
class B extends Base
class C extends Base
trait IntValue[T <: Base] {
def value: Int
}
trait SomeApi {
def apply[T <: Base : ClassTag]: Int
}
class ApiUsage(val api: SomeApi) {
def someMethod() = {
println(api[A])
println(api[B])
println(api[C])
}
}
SomeApi#apply 方法应根据 Base 特征的运行时类型返回 Int 值。我知道这个例子没有意义,但我尽量让它简单。在真正的库中,此方法从actor系统返回对基于该类型的akkaactor的引用。
2) 现在,我想使用 ApiUsage 类并通过 implicit 为 Base 特征类型提供值,如下所示:
object Test extends App {
implicit val aValue = new IntValue[A] {
def value: Int = 10
}
implicit val bValue = new IntValue[B] {
def value: Int = 20
}
implicit def defaultValue[T <: Base : ClassTag] = new IntValue[T] {
def value: Int = 30
}
private val api = new SomeApi {
def apply[T <: Base : ClassTag]: Int = findValue[T]
}
private def findValue[T <: Base : IntValue : ClassTag] =
implicitly[IntValue[T]].value
val apiUsage = new ApiUsage(api)
apiUsage.someMethod()
}
我想要做的是创建 ApiUsage 类并将它的引用传递给我的本地实现 SomeApi ,它返回: - A 类型为 10 - B 类型为 20 - 其他类型为 30(本例中为 C)
此测试在所有情况下都打印 30。
有什么方法可以优雅地用隐式解决这个问题?非常感谢
【问题讨论】:
-
SomeApi有什么可以改变的吗?因为我不认为它是这样工作的。您需要为整个调用链提供隐式,否则编译器无法推断。你需要SomeApi { def apply[T <: Base : IntValue] } -
不幸的是,我不能。但是如果签名看起来像你的,我可以想象,然后我将在 ApiUsage 范围内移动隐式,它会起作用
-
如果我是正确的并且考虑到
implicitly写在库内部,并且没有上下文绑定 - 隐式搜索仅在库内本地执行,因此您无法提供隐式实现. -
你可以换一种说法——隐式是在编译时解决的。并且您的库已经被编译。所以所有的隐式都已经解决了