从超类型解析隐式参数

Resolve implicit parameter from super type

如果为其超类型 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"
如果我不告诉 scalac 冬天是一个季节,

Enumeration.name(Winter) 就会失败。我已经指定 'name' 方法签名中的隐式参数是 A 的超类型,但这还不够...

有更好的方法吗?

当您需要推断依赖于类型的类型时,这是一个常见的不便之处。你的方法

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)

Eduardo 的回答解释了为什么带有 [A, T >: A] 的版本不起作用。但是这个问题有一个比他给出的更简单的解决方案:不是引入 T infer 作为类型参数,而是通过存在类型引入它:

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

或者,使用 shorthand、

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

那么编译器只需要在查找ev.

时决定T是什么