解析超类型的隐式参数

问题描述:

如果为其超类型A定义了隐式,是否可以解析类型B的隐式参数?解析超类型的隐式参数

下面是一个例子:

我有一个可枚举类型类:

trait Enumerable[A] { 

    def name(a: A): String 

    def list: List[A] 

    //... other methods 
} 

object Enumeration { 
    def name[A, T >: A](a: A)(implicit ev: Enumerable[T]) = ev.name(a) 

    def list[T](implicit ev: Enumerable[T]) = ev.list 

    // ... 
} 

然后我定义枚举的一个实例:

sealed trait Season 

case object Winter extends Season 
case object Spring extends Season 
case object Summer extends Season 
case object Fall extends Season 

implicit val seasonEnumerable = new Enumerable[Season] { 
    override def list: List[Season] = List(Winter, Spring, Summer, Fall) 
} 

// working : 
Enumeration.name(Winter: Season) shouldBe "winter" 

// faling : 
Enumeration.name(Winter) shouldBe "winter" 

Enumeration.name(冬)是,如果失败我不告诉scalac冬天是一个季节。我已经指定'name'方法签名中的隐式参数是A的超类型,但它是不够的...

有没有更好的方法来做到这一点?

Eduardo的回答解释了为什么与[A, T >: A]版本不起作用。但有一个解决问题的简单的解决方案比他给人的:不是引入T推断的类型参数,介绍它由生存型:

def name[A](a: A)(implicit ev: Enumerable[T >: A] forSome { type T }) = ev.name(a) 

或者使用简写,

def name[A](a: A)(implicit ev: Enumerable[_ >: A]) = ev.name(a) 

然后编译器只需要决定什么时候寻找ev就是T

+0

确实!谢谢:) 你能否解释一下def name [A](a:A)(implicit ev:Enumerable [_>:A])= ev.name(a) 和def name [A,T>: A](a:A)(隐式ev:Enumerable [T])= ev.name(a)? – Loic

+1

我已经扩大了答案。 –

无论何时您需要推断依赖于类型的类型,这都是常见的不便之处。你的方法

def name[A, T >: A](a: A)(implicit ev: Enumerable[T]) 

呼吁Winter时,第一A会被推断为Winter.type然后TA,因为它符合该约束,并有在这一点上没有更多的约束。那么编译器当然不会找到Enumerable[Winter.type]的实例。

有与类型成员虽然一个简单的解决方案:

trait AnyEnumerable { 

    type E 

    def name[A <: E](a: A): String 
    def list: List[E] 
} 

object Enumeration { 

    def name[A](a: A)(implicit ev: AnyEnumerable { type E >: A }) = ev.name(a) 
    def list[T](implicit ev: AnyEnumerable { type E = T }) = ev.list 
    // ... 
} 

// an implicit for `Season` 
implicit val seasonEnumerable: AnyEnumerable { type E = Season } = 
    new AnyEnumerable { 

    type E = Season 

    def name[A <: Season](a: A): String = a.toString 
    def list: List[Season] = List(Winter, Spring, Summer, Fall) 
    } 

// compiles! 
val zzz = Enumeration.name(Winter)