Case Class

概述

Case class是具有如下特点的普通类:
1. 默认情况下不可对属性(fields)进行修改;
2. 在模式匹配时会进行解构(unapply);
3. 两个case class进行比较时进行全等比较(Compared by structural;也称为按值比较,Comparison-by-value),而非按是否引用同一个对象进行比较(也即指针值是否相等);
4. 简洁地实例化(不需要使用new关键字)及其它操作语法。


使用原因

使用case class组织数据(model/group data)可以帮助写出更有表达力、更易维护的代码,具有原因如下:

  1. 默认情况下不可修改属性值可以避免过分关注在何时、何地对其进行修改;
  2. 全等比较可以将它们作为基本值进行比较,而无需关心实例到底是值还是引用(value or reference);
  3. 支持模式匹配来简化分支逻辑,可以减少bugs并提高代码可读性。

特点

1 实例化一个case class比较简单(无须添加new关键字)。

case class Persion(name: String, age: Int)

val me = new Persion("Yuan Jianzheng", 26)
val stillMe = Persion("Yuan Jianzheng", 26) //两种语法均可

2 case class构造函数的参数会被当作可被直接访问的具有public控制级别的属性值。

println(me.name) //Yuan Jianzheng

3 case class默认情况下不能直接修改其属性值(fields),除非你在声明case class时在相应域前添加”var”关键字(默认情况下是”val”,但并不鼓励如此使用)。

case class PersionAlias(var name: String, var age: Int)

val me = Persion("Yuan Jianzheng", 26)
val meAlias = PersionAlias("Yuan Jianzheng", 26)

me.age = 27 //Error
meAlias.age = 27

4 case class提供了一个copy方法,可以使用其在原有实例基础上通过修改一些域(或属性)来生成新的实例。

val me = Persion("Yuan Jianzheng", 26)
val nameSakeMan = me.copy(age = 27) //具名参数,可以不在意顺序
val name1SakeMan = me.copy("Yuan Jianzheng", 27) //不具名参数,需要严格保证参数的顺序性

5 编译会为case class实例自动生成一些方法:

equals方法:用于对case class实例进行全等比较(也即结构相等,Structural Equality)。

val me = Persion("Yuan Jianzheng", 26)
val stillMe = Persion("Yuan Jianzheng", 26)

me == stillMe //True

toString方法:用于获取case class实例的一些基本信息。

val me = Persion("Yuan Jianzheng", 26)
val info = me.toString
val info1 = "" + me //两者的值均为Persion(Yuan Jianzheng, 26)

hashCode方法:用于获取case class实例的hashCode值(每一个对象都有一个唯一的hashCode值,有时hashCode的实现是将对象内部地址转换为Int值而来)。

val meHashCode: Int = me.hashCode()

6 case关键字被同时用于match表达式中的case表达式并不是巧合,case class的特性就是为更便捷地进行模式匹配而设计的。

val me = Persion("Yuan Jianzheng", 26)

me match {
  case Persion(name, _) => println("Name is: " + name)
  case _ => println("The type is not Persion")
}

7 编译器会为case class生成相对应的伴生对象(Companion Object,是一个与此case class同名的单例对象),此伴生对象中会自动添加一些方法:

apply工厂方法(该方法接受的参数列表与构造函数接受的参数列表一致),用于构造对象(相当于调用new操作)。

unapply方法,用于提取和”解构”,当遇到match case的模式匹配表达式时,就会调用该方法(可嵌套调用)。所有unapply方法的返回值类型均为Option[TupleN[…]],这里的N表示从对象中提取的值的个数,被提取的值类型与相应位置元组元素类型一致。在进行匹配时,编译器将元组元素与字面进行比较,或者赋值给我们已命名的变量,亦或者用占位符”_”丢掉不需要的元素。由此可推测Persion类的伴生对象如下:

object Persion {
  def apply(name: String, age: Int) = new Persion(name, age)

  def unapply(p: Persion) = Option[Tuple2[String, Int]] = Some((p.name, p.age))
}

unapply方法返回类型为Option的原因:

Scala允许unapply方法“否决”这个匹配,返回None,这时Scala会使用下一个case子句。另外,如果我们不希望暴露case class所有属性的话,可以隐藏部分属性(在case语句中使用占用符”_”隐藏单个属性)。为了获得性能上的优势,Scala 2.11.1放松了对unapply方法返回Option[T]的要求,现在其能返回任意类型,只要该类型具有如下方法:

def isEmpty: Boolean
def get: T

8 Scala不允许同时使用implicit和case关键字,也即,隐式类不能同时是一个case类。这是由于case类不会执行通过隐式所生成的额外代码,因此隐式case类本身也就没有任何意义。

参考

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值