从超类型中解析隐式参数

时间:2016-11-28 08:53:30

标签: scala typeclass superclass implicit type-members

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

以下是一个例子:

我有一个可枚举的类型类:

driver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(0,0,10));

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

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

  // ...
}

如果我不告诉scalac Winter是一个季节,那么Enumeration.name(Winter)就会失败。我已经指定了' name'中的隐含参数。方法签名是A的超类型,但它还不够......

有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

每当您需要推断类型相关类型时,这是一个常见的不便。你的方法

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

Winter上调用时,首先将A推断为Winter.type,然后将T推断为A,因为它符合该界限在那一点上没有更多的约束。然后编译器当然找不到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)

答案 1 :(得分:3)

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)

然后编译器只需要在查找T时决定ev是什么。