Scala抽象类型成员 - 继承和类型边界

Mic*_*ier 4 scala abstract-type type-bounds type-members

今天我在Scala遇到了一些奇怪的情况,当时我试图改进抽象类型成员的类型边界.

我有两个特性定义类型成员的边界,并将它们组合在一个具体的类中.这工作正常但是当匹配/转换特征组合时,两个TypeBounds中只有一个是"活跃的",我很难理解为什么......

我试着准备一个例子:

trait L
trait R

trait Left {
  type T <: L
  def get: T
}

trait Right {
  type T <: R
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我将这两个特征结合在一个具体的类中

val concrete = new Left with Right {
  override type T = L with R
  override def get: T = new L with R {}
}
Run Code Online (Sandbox Code Playgroud)

我可以按预期访问我的会员

// works fine
val x1: L with R = concrete.get
Run Code Online (Sandbox Code Playgroud)

但是如果我转向(左边右边)或模式匹配我再也无法访问该成员了.根据顺序,我从左或右获得类型边界,但不是两者的组合.

// can only access as R, L with R won't work
val x2: R = concrete.asInstanceOf[Left with Right].get

// can only access as L, L with R won' work
val x3: L = concrete.asInstanceOf[Right with Left].get
Run Code Online (Sandbox Code Playgroud)

我知道Left with Right与Right with Left不同,但在这两种情况下都包含了两个类型边界,为什么我只能得到一个工作?

任何人都可以解释为什么会发生这种情况?

Gio*_*tti 9

第二个类型成员覆盖第一个类型.

trait L
trait R

trait Left {
  type T <: L
  def get: T
}

trait Right {
  type T <: R
}

object X {
  type LR = Left with Right // Right#T overrides Left#T, LR#T is now <: R
  type RL = Right with Left // Left#T overrides Right#T, LR#T is now <: L

  val concrete = new Left with Right {
    override type T = L with R
    override def get: T = new L with R {}
  }

  // ok
  val r: R = concrete.asInstanceOf[LR].get
  val l: L = concrete.asInstanceOf[RL].get

  // ok
  implicitly[LR#T <:< R]
  implicitly[RL#T <:< L]

  // doesn't compile, LR#T is a subclass of R because Right#T overrides Left#T
  implicitly[LR#T <:< L]
  // doesn't compile, RL#T is a subclass of L because Left#T overrides Right#T
  implicitly[RL#T <:< R]
}
Run Code Online (Sandbox Code Playgroud)

在"具体"中,你覆盖了类型成员L with R,但是当你将它Left with Right强制转换为遗失时,T会变成_ <:L或_ <:R,具体取决于特征的顺序.

由于类型成员可以被覆盖,如果你向上转换(例如LR或RL),你将失去在混凝土中应用的细化.你可以说混凝土同时是一个RL和一个LR,但是当你将它向上转换为LR或RL时,你会失去你在另一个中获得的信息.