【问题标题】:case class and inheritance: how to offer different behaviour案例类和继承:如何提供不同的行为
【发布时间】:2013-05-15 11:28:36
【问题描述】:

情况:

trait Operation {
def something: Double 
}

trait OperationPlus { this: A =>
override def something: Double = x + y
}
trait OperationMinus { this: A =>
    override def something: Double = x - y
}

case class A(x: Double, y: Double) { this:  Operation =>
}

val a = new A(1.0, 2.0) with OperationPlus
  println(a.something)

错误:

class A cannot be instantiated because it does not conform to its self-type A with Operation

另外,我无法实例化 A。

我尝试了多种不同的方法,但都没有提供我正在寻找的东西。我不想使用案例类继承,或者放弃案例类,理想情况下,特质/自我类型/其他东西应该可以解决问题。有什么想法吗?

更新 首选解决方案

 trait Operation { this: A =>
 def something: Double 
 }

 trait OperationPlus extends Operation { this: A =>
   override def something: Double = x + y
 }
 trait OperationMinus extends Operation { this: A =>
     override def something: Double = x - y
 }

 abstract case class A(val x: Double, val y: Double) extends Operation

 val a = new A(1.0, 2.0) with OperationPlus
 println(a.something)

 val b = new A(1.0, 2.0) with OperationMinus
 println(b.something)

可能的解决方案1:

trait Operation {
  def x:Double 
  def y:Double
  def something: Double 
}

trait OperationPlus extends Operation {
  override def something: Double = x + y
}
trait OperationMinus extends Operation {
      override def something: Double = x - y
}

abstract case class A(val x: Double, val y: Double) extends Operation 

通过使用常规类,简单的 trait 继承和实际值中的 self-type 可以定义它并动态提供行为。

不幸的是,我必须重新定义特征中的字段。我想这是一个公平的妥协。有兴趣知道是否有人知道另一种方法。

谢谢

【问题讨论】:

    标签: scala case-class traits self-type


    【解决方案1】:

    不确定你的用例,但如果你想让它工作,你需要像这样定义类A

    abstract case class A(x: Double, y: Double) extends Operation
    

    但我不认为用例类的惯用方法。它们主要用作数据容器,通常不包含任何行为。 (也许你可以告诉更多关于你想用这个实现的事情的信息)

    【讨论】:

    • 感谢@tenshi,如果我将案例类抽象化,我将无法实例化它。我想做的是一个经典的面向对象的父类,每个子类定义一个方法。但是,这些方法可以被不同的层次结构重用,所以我想把它作为一个基本特征。我只是找不到如何提取它。
    • @fracca 你仍然可以通过混合一些操作来实例化它:new A(1.0, 2.0) with OperationMinus。但是在您的示例方法中 something 是抽象的,因此您需要定义它或使整个类抽象。或者你可以直接在A类中扩展OperationMinusOperationPlus,不要声明为abstract。
    • 抽象案例类有效地允许人们保留案例类的好处以及混合行为。但是由于something操作是在A的基础上定义的,所以需要重新定义字段x和y。
    【解决方案2】:

    首先,您应该:

    trait OperationPlus extends Operation
    trait OperationMinus extends Operation
    

    其次,您不能将A 定义为案例类,因为它会自动在伴随对象上定义apply 方法,其中调用new A(带有参数)。由于错误的自我类型(您看到的错误),此调用失败。

    删除case。如果您需要模式匹配,请自己定义一个提取器(实现unapply):

    class A(val x: Double, val y: Double) { this: Operation => }
    
    object A {
      def unapply(v: A) = Some((v.x, v.y))
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-02
      • 1970-01-01
      • 1970-01-01
      • 2018-03-14
      • 1970-01-01
      • 2013-05-02
      • 1970-01-01
      相关资源
      最近更新 更多