这是我的问题,我有一个像这样定义的类型类:
trait Alterer[T] {
def alter(t: T): T
}
object Alterer {
implicit val stringPrinter = new Alterer[String]{
override def alter(s: String) = "hi " + s
}
}
object Alter {
def alter[T](obj: T)(implicit alterer: Alterer[T]) = alterer.alter(obj)
}
val bob2 = Alter.alter("bob") // hi bob
现在我想为其他类型定义隐式实例。 但我希望能够定义一个超类型。 Any作为超类型的示例:
case class Person(name: String, age: Int)
implicit val anyPrinter = new Alterer[Any]{
override def alter(a: Any) = ("hi any " + a.toString)
}
Alter.alter(Person("joe", 34))
这不会编译,因为如果我想让Alterer [Any]被视为Alterer [Person],我的T类型必须是逆变的。
所以我会这样做:
trait Alterer[-T] {
def alter(t: T): T
}
如果alter方法也没有返回T,那就没关系。 这里编译器抱怨因为T返回类型不在逆变位置。
有没有办法解决这个问题?
由于
答案 0 :(得分:1)
您需要两个类型参数,一个用于逆变输入,另一个用于协变输出。
trait Alterer[-T, +U] {
def alter(t: T): U
}
然后你可以宣布一个
implicit val stringPrinter = new Alterer[String, String]{
override def alter(s: String) = "hi " + s
}
对于字符串或
implicit val anyPrinter = new Alterer[Any, String]{
override def alter(a: Any) = ("hi any " + a.toString)
}
将Any转换为字符串并预先发布“hi any”
如果你想强制输入和输出之间的子类型关系,你可以使用一个抽象类来代替你的特性,该抽象类在其构造函数中接受一个子类型证据。
abstract class Alterer[-T, +U](implicit ev: U <:< T) {
def alter(t: T): U
}
<:<
在predef中定义,并强制U是T的子类型。
此更改后,其余代码保持不变。