【问题标题】:How to override implicits for types如何覆盖类型的隐式
【发布时间】: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系统返回对基于该类型的akka​​actor的引用。

2) 现在,我想使用 ApiUsage 类并通过 implicitBase 特征类型提供值,如下所示:

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 &lt;: Base : IntValue] }
  • 不幸的是,我不能。但是如果签名看起来像你的,我可以想象,然后我将在 ApiUsage 范围内移动隐式,它会起作用
  • 如果我是正确的并且考虑到implicitly 写在库内部,并且没有上下文绑定 - 隐式搜索仅在库内本地执行,因此您无法提供隐式实现.
  • 你可以换一种说法——隐式是在编译时解决的。并且您的库已经被编译。所以所有的隐式都已经解决了

标签: scala implicit-conversion


【解决方案1】:

在不改变签名的情况下你能做的最好的可能是

val api = new SomeApi {
  def apply[T <: Base : ClassTag]: Int = {
    val clazz = classTag[T].runtimeClass
    if (clazz == classOf[A]) 
      10
    else if (clazz == classOf[B]) 
      20
    else 
      30
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    • 1970-01-01
    • 2018-11-22
    • 1970-01-01
    相关资源
    最近更新 更多