Scala的情况下,类继承(Scala case class inheritance)

2019-06-18 11:00发布

我有一个基于Squeryl的应用程序。 我定义我的模型作为案例类,主要是因为我觉得方便的复制方法。

我有两个模型是严格相关。 该字段是相同的,很多操作都是常见的,它们将被存储在同一个数据库表。 但是,有一些行为才有意义在这两种情况之一,或者是有道理的在这两种情况下却是不同的。

到现在为止我只使用了一个单例类,与区分模型的类型的标志,而有所不同基于模型的类型的所有方法都以如果。 这是烦人,不完全类型安全。

我想这样做是因素祖先案例类的常规行为和领域,并有两个实际车型继承它。 但是,据我了解,从案例类继承在斯卡拉令人难以接受的,如果子类本身就是一个案例类(没有我的情况下),甚至禁止。

什么是我应该知道从的情况下,类继承的问题和隐患? 是否有意义我的情况下这样做呢?

Answer 1:

我的优选避免壳体类继承不重复的代码的方法是有点明显:创建一个公共(抽象)基类:

abstract class Person {
  def name: String
  def age: Int
  // address and other properties
  // methods (ideally only accessors since it is a case class)
}

case class Employer(val name: String, val age: Int, val taxno: Int)
    extends Person

case class Employee(val name: String, val age: Int, val salary: Int)
    extends Person


如果你想更细粒度,组的属性为个人特质:

trait Identifiable { def name: String }
trait Locatable { def address: String }
// trait Ages { def age: Int }

case class Employer(val name: String, val address: String, val taxno: Int)
    extends Identifiable
    with    Locatable

case class Employee(val name: String, val address: String, val salary: Int)
    extends Identifiable
    with    Locatable


Answer 2:

由于这是许多有趣的话题,让我提供一些线索在这里。

你可以用下面的方法去:

// You can mark it as 'sealed'. Explained later.
sealed trait Person {
  def name: String
}

case class Employee(
  override val name: String,
  salary: Int
) extends Person

case class Tourist(
  override val name: String,
  bored: Boolean
) extends Person

是的,你要复制的字段。 如果你不这样做,它根本就不可能实现平等的正确其他问题之一 。

不过,你不需要复制方法/函数。

如果几个属性的复制是非常对你的重要性,然后用普通班,但请记住,他们不适合FP很好。

另外,您也可以使用,而不是组成继承:

case class Employee(
  person: Person,
  salary: Int
)

// In code:
val employee = ...
println(employee.person.name)

组合物是有效的,并且你应该考虑,以及健全的策略。

而如果你想知道一个密封的特点意味着 - 它是什么,只能在同一个文件进行扩展。 也就是说,这两种情况下,上面的类必须在同一个文件。 这允许详尽的编译器检查:

val x = Employee(name = "Jack", salary = 50000)

x match {
  case Employee(name) => println(s"I'm $name!")
}

给出了一个错误:

warning: match is not exhaustive!
missing combination            Tourist

这是非常有用的。 现在,你不会忘记对付其他类型的Person S(人)。 这基本上什么是Option Scala的类一样。

如果这不要紧,你,那么你可以把非密封和case类扔进自己的文件。 并与成分也许去。



Answer 3:

case类是完美的值对象,不改变任何属性,并可以用等号进行比较,即对象。

但是,在继承的情况下实现equals比较复杂。 考虑两个类:

class Point(x : Int, y : Int)

class ColoredPoint( x : Int, y : Int, c : Color) extends Point

因此,根据该定义的重点色(1,4,红色)应该等于该点(1,4),它们是相同的点毕竟。 所以重点色(1,4,蓝)也应该等于点(1,4),对不对? 但是,当然,重点色(1,4,红色)应不等于重点色(1,4,蓝),因为他们有不同的颜色。 你去那里,平等关系的一个基本属性是坏了。

更新

您可以使用继承自性状解决很多的问题,在另一个答案描述。 一个更灵活的选择往往是使用类型类。 看看什么是Scala的类型类有用吗? 或http://www.youtube.com/watch?v=sVMES4RZF-8



Answer 4:

在这种情况下,我倾向于使用组成,而不是继承,即

sealed trait IVehicle // tagging trait

case class Vehicle(color: String) extends IVehicle

case class Car(vehicle: Vehicle, doors: Int) extends IVehicle

val vehicle: IVehicle = ...

vehicle match {
  case Car(Vehicle(color), doors) => println(s"$color car with $doors doors")
  case Vehicle(color) => println(s"$color vehicle")
}

显然,你可以使用更复杂的层次和比赛,但希望这给你的想法。 关键是要采取嵌套提取这种情况下,类提供的优势



文章来源: Scala case class inheritance