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())//
println(docA.hashCode())//

貌似这时候case class就不会生成equals方法了, 转而使用父类Person的equals方法。并且要记得同时在Person中覆盖hashCode方法,不然就破坏了equals对hashCode的要求。

case class inheritance的更多相关文章

  1. Three Sources of a Solid Object-Oriented Design

    pingback :http://java.sys-con.com/node/84633?page=0,1 Object-oriented design is like an alloy consis ...

  2. C#调用C++导出类(转)

    由于使用别人的Dll,导出的是一个实体类,在C#里封送很难,百度下,有个朋友回复一篇英文的,虽然不一定使用,但可以作为一个知识点,现把原文贴下: c#调用C++写的dll导出类,包含继承,重载等详细介 ...

  3. TFS 2015 Build Agent failing syncing the repository 获取源码 不全 失败

    当我们使用TFS2015d的生成代理时,我们将生成定义加入代理池队列中,但是代理可能无法完全下载我们在TFS代码浏览器中看到的所有目录,这肯定会导致编译失败呀!为什么呢? 原因在于tfscompile ...

  4. Ubuntu+apache安装redmin

    公司要迁移redmin,本来以为是一个很简单的项目,想不到整整搞了一天加一个晚上. 首先是对ruby的安装不熟悉,现在明白了ruby的安装顺序是先安装rvm版本管理,然后用rvm安装ruby,安装好后 ...

  5. The IDL compiler

    The IDL compiler or bindings generator transcompiles Web IDL to C++ code, specifically bindings betw ...

  6. C++: virtual inheritance and Cross Delegation

    Link1: Give an example Note: I think the Storable::Write method should also be pure virtual. http:// ...

  7. JavaScript Patterns 6.2 Expected Outcome When Using Classical Inheritance

    // the parent constructor function Parent(name) { this.name = name || 'Adam'; } // adding functional ...

  8. Effective Java 17 Design and document for inheritance or else prohibit it

    Principles The class must document its self-use of overridable methods. A class may have to provide ...

  9. Think Python - Chapter 18 - Inheritance

    In this chapter I present classes to represent playing cards, decks of cards, and poker hands.If you ...

随机推荐

  1. virtualbox下Centos6.5桥接模式上网配置方法

    记得之前安装linux配置桥接模式,马上就能上网的,虚拟机上重装了系统后就不能上网了,折腾了好几次,不停地安装系统,原来应该怎么配置,我真是完全忘记了,年纪大了脑子不好使了!这里记录一下,免得下次再忘 ...

  2. VR开发中性能问题—OculusWaitForGPU

    http://blog.csdn.net/cartzhang/article/details/50788894 VR开发中性能问题-OculusWaitForGPU 本文章由cartzhang编写,转 ...

  3. Swift闭包(Closure)

    语法: { (parameters) ->return type in statements} 实例:采用函数实现: let names =["Chris", "A ...

  4. swift基础知识学习

    用let来声明常量,用var来声明变量   声明变量: var x = 0.0, y = 0.0, z = 0.0 var welcomeMessage: String 常量和变量的命名 你可以用任何 ...

  5. 在ASP.NET中实现压缩多个文件为.zip文件,实现批量下载功能 (转载并优化处理篇)

    转自:http://blog.csdn.net/yanlele424/article/details/6895986 这段时间一直在做一个网站,其中遇到了一个问题,就是在服务器端压缩多个服务器端的文件 ...

  6. [C#]线程处理

    线程处理用于使程序能够执行并发处理,同时执行多个操作.C#中有三种线程的使用方法,BackgroundWorker组件.线程池.自己创建使用线程,接下来分别介绍如何使用. 1.使用Background ...

  7. 对C#调用C++ dll文件进行总结

    在实际项目工作中,经常用到C#调用C++ 或者C编写的dll文件. dll支持一般函数声明和类的定义声明,但是一般为了简化,都是 采用函数声明的方式.这里主要并不是写 dll的编写. 先在vs中创建一 ...

  8. 面向切面的Spring

    在软件开发中,发布于应用中多处的功能被称为横切关注点.通常,这些横切关注点从概念上是与应用的业务逻辑相分离的(但往往直接嵌入到应用的业务逻辑之中).将横切关注点与业务逻辑相分离是AOP所要解决的. 一 ...

  9. Ubuntu 下 glpk 的安装及使用

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4156204.html glpk是一个开源的求解线性规划的包. 添加源: deb http:/ ...

  10. asp.net导出Excel

    注意这种方法,导出的excel没有网格线 当在导出Execl或Word的时候,会发生只能在执行 Render() 的过程中调用 RegisterForEventValidation的错误提示.下面的2 ...