这是我的问题,我有一个这样定义的类型类:

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/

10-16 05:48