如果为其超类型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的超类型,但它还不够......
有更好的方法吗?
答案 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
是什么。