从超类型解析隐式参数
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
是什么
如果为其超类型 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
是什么