Scala:Class 具有其构造函数采用另一个具有一组并行特征的 class 的特征?

Scala: Class with traits whose constructor takes another class with a parallel set of traits?

假设我有一个具有一组混合特征的 class A,以及一个值为 class A 的 class B。有没有办法 class B 拥有一组混合特征,要求 A 依次具有某些特征(包括继承自多个其他此类特征的 B 的特征)?

示例:

trait A
trait Ax extends A
trait Ay extends A

class B(val a: A)               // Should be traits,
class Bx(ax: Ax) extends B(ax)  // but traits can't
class By(ay: Ay) extends B(ay)  // take parameters

class Bxy extends Bx with By    // Can't mix in classes

有没有什么方法可以让 Bxy 既继承自 Bx 和 By,又需要具有 Ax 和 Ay 特征的 A 值?

编辑 -- 这是一个可能更清楚的替代(仍然无效)示例:

class A
trait Ax extends A { def doAx: String = "Ax method" }
trait Ay extends A { def doAy: String = "Ay method" }

class B(val a: A)

trait Bx extends B {
  require(a.isInstanceOf[Ax])
  def doBx: String = a.doAx    // Ax methods not actually accessible here
}

trait By extends B {
  require(a.isInstanceOf[Ay])
  def doBy: String = a.doAy    // Nor Ay methods here
}

class Bxy(a: A with Ax with Ay) extends B(a) with Bx with By {
  def doBxy: String = a.doAx + a.doAy
}

我无法在注释中加入代码来澄清,但鉴于以下内容,您希望 a 变量发生什么?

trait A
trait Ax extends A
trait Ay extends A

trait B {
  val a: A
}

trait Bx extends B {
  val x: Ax
}

trait By extends B {
  val y: Ay
}

class Bxy(ax: Ax, ay: Ay) extends Bx with By {
  val a = ??? // what do you want `a` to become here?
  val x = ax
  val y = ay
}

用不同的类型覆盖 a

trait A
trait Ax extends A
trait Ay extends A

trait B {
  val a: A
}

trait Bx extends B {
  val a: Ax
}

trait By extends B {
  val a: Ay
}

然后:

class Bxy(ax: Ax, ay: Ay) extends Bx with By {
  val a = ay
}

不可能,因为 ay 不是 Ax。同样,val a = ax 是不可能的,因为 ax 不是 Ay.

您可以使 B 成为特征,抽象 class,或采用通用 A。这是一个 B 是特征的示例:

class A
trait Ax extends A { def doAx: String = "Ax method" }
trait Ay extends A { def doAy: String = "Ay method" }

trait B {
  val a: A
}

trait Bx extends B {
  val a: Ax
  def doBx: String = a.doAx
}

trait By extends B {
  val a: Ay
  def doBy: String = a.doAy
}

class Bxy(val a: Ax with Ay) extends Bx with By {
  def doBxy: String = a.doAx + a.doAy
}

您可以使用 apply 方法使用特征和伴随对象来模拟这一点。

trait A
trait Ax extends A { def doAx = "Ax method" }
trait Ay extends A { def doAy = "Ay method" }

trait B {
    val a: A
}

object B {
    def apply(aa: A): B = new B {
        val a = aa
    }
}

trait Bx extends B {
  val a: Ax
  def doBx = a.doAx
}

object Bx {
    def apply(ax: Ax): B = new Bx {
        val a: Ax = ax
    }
}

trait By extends B {
  val a: Ay
  def doBy = a.doAy
}

object By {
    def apply(ay: Ay): B = new B {
        val a: Ay = ay
    }
}

class Bxy(val a: Ax with Ay) extends Bx with By {
  def doBxy = a.doAx + a.doAy
}

伴随对象 BBxBy 将充当其伴随特征的工厂,匿名创建它们。

val a = new A {}
val ax = new Ax {}
val ay = new Ay {}
val axy = new Ax with Ay {}

scala> B(a)                       
res0: B = B$$anon@62f4ad6f      

scala> Bx(ax)                     
res1: B = Bx$$anon@1436dd6f     

scala> By(ay)                     
res2: B = By$$anon@6e84ee94     

scala> new Bxy(axy)               
res5: Bxy = Bxy@480101a7          

scala> res5.doBxy                 
res6: String = Ax methodAy method