您的位置:首页 > 其它

case class inheritance

2015-04-23 22:04 260 查看
Scala 禁止case class inheritance

case class Person(name: String, age: Int)
case class FootballPlayer(name: String, age: Int, number: Int) extends Person(name, age)


在编译时会报出以下错误:


Error:(5, 12) case class FootballPlayer has case ancestor Person, but case-to-case inheritance is prohibited. To overcome this limitation, use extractors to pattern match on non-leaf nodes.
case class FootballPlayer(name: String, age: Int, number: Int) extends Person(name, age)
^


原因有挺多,下边的两篇文章讲了下理由,但我还是没明白其中的必要性。
http://tech.schmitztech.com/scala/caseclassinheritence.html http://stackoverflow.com/questions/11158929/what-is-so-wrong-with-case-class-inheritance
我们可以使得两个case class继承同一个trait来实际于case class继承的行为,但是这样就得自己写extractor了。比如

sealed trait Person{
def age: Int
def name: String
}
case class FootballPlayer(name: String, age: Int, number: Int) extends Person
val torres = FootballPlayer("Fernando Torres", 31, 19)
val Person(name, age) = torres // can't resolve symbal Person


会编译出错, 因为Person是个trait,它并不支持extractor的语法。

需要给Person加个Companion object,像这样

object Person{
def unapply(p: Person) = Some((p.name, p.age))
}


这时就能用extractor了

val torres = FootballPlayer("Fernando Torres", 31, 19)
val Person(name, age) = torres


编译器会为case class生成equals方法,但普通类就不会了。

  sealed trait Person{
def age: Int
def name: String
}

case class FootballPlayer(name: String, age: Int, number: Int) extends Person
class Doctor(val name: String, val age: Int) extends Person
val torresA = FootballPlayer("Fernando Torres", 31, 19)
val torresB = FootballPlayer("Fernando Torres", 31, 19)
println(torresA == torresB)//true

val docA = new Doctor("C", 30)
val docB = new Doctor("C", 30)
println(docA == docB)//false


这时,当两个FootballPlayer的构造参数相同,它们就相等。但是对于Doctor类来说不是这样了。

当给FootballPlayer这个case class的父类Person定义了equals方法之后,就不是这样了。

sealed trait Person{self =>
def age: Int
def name: String
override def equals(that: Any):Boolean = {
that match{
case p: Person => p.age == self.age && p.name == self.name
case _ => false
}
}
override def hashCode: Int = {
var hash = 1
hash = hash * 31 + age
hash = hash * 31 + {if(name !=null) name.hashCode else 0}
hash
}
}
case class FootballPlayer(name: String, age: Int, number: Int) extends Person
class Doctor(val name: String, val age: Int) extends Person
val torresA = FootballPlayer("Fernando Torres", 31, 19)
val torresB = FootballPlayer("Fernando Torres", 31, 19)
torresA.equals(torresB)
println(torresA == torresB)//true

val docA = new Doctor("C", 30)
val docB = new Doctor("C", 30)
println(docA == docB) //true

val footballPlayerC = FootballPlayer("C", 30, 30)
println(footballPlayerC == docA) //true
println(footballPlayerC.hashCode())//1958
println(docA.hashCode())//1958


貌似这时候case class就不会生成equals方法了, 转而使用父类Person的equals方法。并且要记得同时在Person中覆盖hashCode方法,不然就破坏了equals对hashCode的要求。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: