【问题标题】:Scala: Class with traits whose constructor takes another class with a parallel set of traits?Scala:具有特征的类,其构造函数采用另一个具有一组并行特征的类?
【发布时间】:2015-07-05 20:17:26
【问题描述】:

假设我有一个具有一组混合特征的类 A 和一个具有类 A 值的类 B。有没有办法让 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
}

【问题讨论】:

  • 你为什么需要它?
  • 如果你想向 B 添加功能,需要它的 A 实例依次具有某些功能。
  • Bxy 仍然只接受一个参数,并且只保存一个 A 值。我不想在 A 的 Ax 和 Ay 版本之间进行选择,我想要一个同时具有这两个特征的 A。
  • Bx 和 By 不会向类添加值——只是对传递给 B 类构造函数的单个参数添加限制。 (我添加了一个替代示例来澄清这一点。)

标签: scala class constructor multiple-inheritance traits


【解决方案1】:

您可以通过 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$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 

【讨论】:

    【解决方案2】:

    我无法在注释中添加代码来澄清,但鉴于以下情况,您希望 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

    【讨论】:

    • Bx 和 By 的用意不是给 B 添加新的 A 值,而是限制原 a 值的类型。
    • 查看答案的第二部分,我解释了为什么这是不可能的。
    • 但我不想要class Bxy(ax: Ax, ay: Ay),我想要class Bxy(axy: Ax with Ay)——它应该适用于Bx 和By,因为axy 既是Ax 又是Ay。
    • Ax with Ay 的类型是什么?
    • A = 水果,Ax = 香蕉,Ay = 橙子,我们如何将“香蕉与橙子”合二为一?
    【解决方案3】:

    您可以将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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-26
      • 1970-01-01
      • 2012-10-22
      • 2017-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多