case class inheritance
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的更多相关文章
- 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 ...
- C#调用C++导出类(转)
由于使用别人的Dll,导出的是一个实体类,在C#里封送很难,百度下,有个朋友回复一篇英文的,虽然不一定使用,但可以作为一个知识点,现把原文贴下: c#调用C++写的dll导出类,包含继承,重载等详细介 ...
- TFS 2015 Build Agent failing syncing the repository 获取源码 不全 失败
当我们使用TFS2015d的生成代理时,我们将生成定义加入代理池队列中,但是代理可能无法完全下载我们在TFS代码浏览器中看到的所有目录,这肯定会导致编译失败呀!为什么呢? 原因在于tfscompile ...
- Ubuntu+apache安装redmin
公司要迁移redmin,本来以为是一个很简单的项目,想不到整整搞了一天加一个晚上. 首先是对ruby的安装不熟悉,现在明白了ruby的安装顺序是先安装rvm版本管理,然后用rvm安装ruby,安装好后 ...
- The IDL compiler
The IDL compiler or bindings generator transcompiles Web IDL to C++ code, specifically bindings betw ...
- C++: virtual inheritance and Cross Delegation
Link1: Give an example Note: I think the Storable::Write method should also be pure virtual. http:// ...
- JavaScript Patterns 6.2 Expected Outcome When Using Classical Inheritance
// the parent constructor function Parent(name) { this.name = name || 'Adam'; } // adding functional ...
- 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 ...
- Think Python - Chapter 18 - Inheritance
In this chapter I present classes to represent playing cards, decks of cards, and poker hands.If you ...
随机推荐
- 三种方式得到LayoutInflater
LayoutInflaterinflater=LayoutInflater.from(this); LayoutInflaterinflater=getLayoutInflater(); Layout ...
- android中数据存储的contentprovider的使用方法
元数据接口 package com.example.contentproviderprojecrt; import android.net.Uri; import android.provider.B ...
- Remote Desktop Connection Manager介绍
Remote Desktop Connection Manager (RDCMan) 是微软Windows Live体验团队的主要开发者 Julian Burger开发的一个远程桌面管理工具.简称为R ...
- Javascript之相册拖动管理
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- kettle列转行
- DOS批处理命令-几个固定名称的变量
批处理中有一些变量的变量名称是固定的,具有特定的意义,接下来,我们来看看这些有特定意义的变量到底有什么意义. 1.%CD% 当前路径的路径名[盘符 + 路径] - 現在のディレクトリ文字列に ...
- 基于AspectJ自定义注解
package com.aspectj.demo.aspect; import java.lang.annotation.ElementType; import java.lang.annotatio ...
- will VS be going to
1.Future - Will vs. Going to 2."Will be doing" vs. "will do" 3.Simple Future
- WiFi相关知识
1. 无线路由器的覆盖范围和带机量 覆盖范围取决于发射功率.接收灵敏度,以及对端的发射功率和接收灵敏度.因为Wi-Fi设备在发出数据包后,一定要等待对方回ACK才会确认发送成功,所以,如果任意一方的发 ...
- Unity编程回忆录之控制物体移动
最新心血来潮,然后开始学习Unity3D游戏开发引擎,对于一个主流的跨平台3D游戏开发引擎,我已经深深的为他着迷了,于是果断的开始学习这个引擎,而且刚刚预装的游戏引擎最新版中4.3版本已经开始原生支持 ...