这是我的问题,我有一个这样定义的类型类:
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
现在,我想为其他类型定义隐式实例。
但我希望能够为 super class 型定义。以Any作为 super class 型的示例:
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返回类型不在反位置。
有办法解决吗?
谢谢
最佳答案
为此,您需要两个类型参数,一个用于协变输入,一个用于协变输出。
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的子类型。更改后,此代码的其余部分保持不变。
关于scala - T需要处于协变和逆变位置时的方差,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42585266/