2015-12-21 139 views
0

implicits我有以下问题,这可能是最好的作为一个例子表明:如何覆盖类型

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#适用方法应返回基于运行时类型的Int值基地特征。我知道这个例子没有意义,但我尽可能简化它。在真实的库中,此方法返回对基于来自actor系统的类型的akka​​ actor的引用。

2)现在,我想用ApiUsage类,并通过隐含,这样的事情对于类型基地性状提供值:

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返回: - 10对于A类型 - 20 型 - 30用于其他类型的(ç在这种情况下)

此测试打印在所有情况下。

有没有什么办法来优雅地解决这个问题的含义?非常感谢

+0

是'SomeApi'东西,你可以改变吗?因为我认为它不是那种方式。您需要为整个调用链提供暗示,否则编译器无法推断。你需要'SomeApi {def apply [T <:Base:IntValue]}' – Archeg

+0

不幸的是,我不能。但是,如果签名看起来像你的那样,我可以想象,那么我将在ApiUsage范围内移动implicits,它将起作用。 –

+0

如果我是正确的,并且'implicitly'写在库内部,并且没有上下文绑定 - 暗示搜索只在本地库中执行,所以你不能提供你的implicits实现。 – Archeg

回答

0

你能做的最好不改变签名可能是

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 
    } 
}