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. 关于蓝牙设备与ios连接后,自动打开一个app

    How to launch an iphone app when an external accessory is either paired over BT or plugged into dock ...

  2. SQL Server2008新特性Filesteam的使用

    Filesteam是SQL Server2008的新特性,它结合了SQL Server和NTFS文件系统,为Blob类型的数据提供了比较高效的存储和访问方案.我们最近的一个项目就是采用SQL Serv ...

  3. Ghost版Win8.1系统企业版下载

    host版Win8.1系统企业版,下载完成后一定要使用校验工具验证GHO文件MD5值,如果不符请不要安装,不然安装失败后果自负.GHO文件路径一定不要带中文,否则无法安装.安装完成第一次进入桌面会黑屏 ...

  4. Xcode7打包上传App Store发生ERROR ITMS-90535 错误解决方法

    两个方法解决  1.如果用不到QQ分享啥的,直接删掉TencentOpenApi这个文件夹. 移除掉这个模块 ..简单粗暴,我就是这么解决的. 2.找到TencentOpenApi_IOS_Bundl ...

  5. Html5+Css3 Banner Animation 多方位移动特效

    背景:朋友问我小米官网的mi4的特效会做吗,可能新接的一个小网站需要用到.一直有打算研究H5C3的一些效果,趁此机会,赶紧学习一下! 效果:如图 素材 HTML: <div class=&quo ...

  6. Normalize [ 浏览器渲染格式化 ]

    /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ /** * 1. Set default font family to san ...

  7. SpringInAction读书笔记--第1章Spring之旅

    1.简化Java开发 Spring是一个开源框架,它的根本使命在于简化java开发.为了降低java开发的复杂性,Spring采取了以下4种关键策略: 基于POJO的轻量级和最小侵入性编程      ...

  8. 一个简单的CS系统打包过程图文版

    一个简单的CS系统打包过程图文版 1.     打包内容 1.1.  此次打包的要求和特点 主工程是一个CS系统: 此CS系统运行的先决条件是要有.Net Framework 3.5: 主工程安装完成 ...

  9. TIMAC 学习笔记(一)

    TIMAC是TI公司推出的基于IEEE 802.15.4的通讯协议栈,编译环境为IAR,使用IAR自带的CLIB库,CLIB库提供了轻量级的C库,它不支持嵌入式C++.适用于RF4CE协议和ZigBe ...

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

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