Scala 在使用隐式类型类(方差 + 多态性)时无法访问 getter 方法



在下面的示例中,我不明白为什么我无法访问M1M2M3类上的 getter 方法。

我需要特征ST协变,以便实现runSeq方法。因此,toto方法需要将U作为T的超类。当我这样做时,我无法再访问参数t的构造函数字段。

如果我删除协方差要求(+T(,一切正常,但我不知道如何实现runSeq方法(特别是它需要接收隐式类型类对象(。

abstract class M
case class M1(s: String) extends M
case class M2(i: Int) extends M
case class M3(b: Boolean) extends M
trait S[+T] {
  def follow(s: String): String
  def toto[U >: T](t: U): String
}
implicit object S1 extends S[M1] {
  val m1 = M1("1") // this is for testing only
  def follow(s: String): String = s + ".M1." + toto(m1)
  def toto[M1](t: M1): String = "toto" + t.s // ERROR: cannot resolve "s"
}
implicit object S2 extends S[M2] {
  val m2 = M2(2) // for testing purposes only
  def follow(s: String): String = s + ".M2." + toto(m2)
  def toto[M2](t: M2): String = "toto" + t.i.toString // ERROR: cannot resolve "i"
}
implicit object S3 extends S[M3] {
  val m3 = M3(true) // for testing purposes
  def follow(s: String): String = s + ".M3." + toto(m3)
  def toto[M3](t: M3): String = "toto" + t.b.toString // ERROR: cannot resolve "b"
}
def run[T: S](s: String): String = implicitly[S[T]].follow(s)
run[M1]("run")
def runSeq(seq: S[M]*)(s: String) =
  seq.foldLeft(s)((st, tg) => run(st)(tg))
runSeq(S3,S2,S1)("runSeq")

你正在使用类型参数进行阴影(例如 M1def toto[M1](t: M1): String = "toto" + t.s(。

考虑到object S1 extends S[M1]trait S[+T] { ... def toto[U >: T](t: U): String },一个合规的toto应该像波纹管一样实现。

def toto[U >: M1](t: U): String = "toto" + t.s

在这种情况下,对于U >: M1,类型系统不能证明ts: String定义的。

那里的类型约束和方差似乎是错误的。

首先,请注意def toto[U >: T](t: U): Stringdef toto(t: Any): String基本相同,因为Any满足任何可能T的界限。这也解释了为什么您无法在 t 中访问 T 的成员。请注意,方差与此无关。

T

只是协变的,因为 runSeq 需要取一个 S[T] 序列,其中包含从 M 派生的各种类型的 T。有没有更好的方法?

def runSeq(seq: S[_ <: M]*)直接与此相对应。但是,您可能会遇到类型擦除问题:给定一个S[_ <: M],您无法知道其实际类型参数或检查M是否属于合适的类型。查找ClassTagTypeTag以查找解决方案。同样,这是一个与方差无关的问题。

最新更新