Scala:具有特征的类,其构造函数接受另一个具有平行特征集的类?

Scala:具有特征的类,其构造函数接受另一个具有平行特征集的类?,scala,class,constructor,multiple-inheritance,traits,Scala,Class,Constructor,Multiple Inheritance,Traits,假设我有一个a类,有一组混合特征,B类的值为a类。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) ex

假设我有一个a类,有一组混合特征,B类的值为a类。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,又继承自Bx,并且需要一个具有特征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
然后:


不可能,因为
ay
不是
Ax
。同样地,
val a=ax
也不可能,因为
ax
不是
Ay
您可以将
B
作为一个特征、抽象类,或采用通用的
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
方法使用traits和伴随对象来模拟这一点

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
}
同伴对象
B
Bx
By
将作为其同伴特征的工厂,匿名创建它们

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$2@62f4ad6f      

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

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

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

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

为什么需要它?如果要向B添加需要其A实例依次具有特定功能的功能,Bxy仍然只接受一个参数,并且只保留一个A值。我不想在A的Ax和Ay版本之间进行选择,我想要求A同时具有这两个特征。Bx和By不会向类添加值——只是向传递给类B构造函数的单个参数添加限制。(我添加了另一个示例来澄清这一点。)Bx和By的目的不是向B添加新的A值,而是限制原始A值的类型。请参阅答案的第二部分,其中我解释了为什么不可能。但我不想要
类Bxy(ax:ax,ay:ay)
,我想要
类Bxy(axy:ax带ay)
--哪个应该与Bx和By一起使用,因为axy既是Ax又是Ay。Ax和Ay的类型是什么?A=水果,Ax=香蕉,Ay=橙色,我们如何将“香蕉和橙色”组合成一个东西?
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
}
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$2@62f4ad6f      

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

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

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

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