Case Class不仅定义了一个类,而且同时创建一个伴生对象,并且默认拥有诸多特性,提供了一种简便的创建类的方式。如果你的类中成员没有那么复杂时,case class是理想的类创建方式。
使用关键字case初始化一个类。
case class Person(firstName: String, lastName: String) {
def name = firstName + " " + lastName
}
scala会自动创建一个类和一个伴生对象。
val dave = new Person("Dave", "Gurnell") // we have a class
// dave: Person = Person(Dave,Gurnell)
Person // and a companion object too
// res: Person.type = Person
同时,scala会预先赋予case class诸多特性。
特性
- 构造参数自动成为类成员
dave.firstName
// res: String = Dave
- 默认toString方法返回构造函数样式
dave
// res: Person = Person("Dave","Gurnell")
-
equals
hashCode
方法通过成员变量进行计算。
以上特性使得case class在集合类,如List,Map,Set中,方便使用。同时意味着我们可以通过比较成员变量来确定两个对象的等价性,而不是通过对比引用地址。
new Person("Noel", "Welsh").equals(new Person("Noel", "Welsh"))
// res: Boolean = true
new Person("Noel", "Welsh") == new Person("Noel", "Welsh")
// res: Boolean = true
-
copy
方法返回一个全新的引用(对象),成员变量完全相同。
dave.copy()
// res2: Person = Person(Dave,Gurnell)
dave.copy() eq res0
// res: Boolean = false
实际上copy
方法接受可选的构造参数,如果参数被指定,复制的全新对象中的成员变量的值是指定的而不是从原来的对象中复制来的。这样允许我们在复制的时候修改某些成员变量的值。
dave.copy(firstName = "Dave2")
// res: Person = Person(Dave2,Gurnell)
- 实现了Serializable
等价性(值还是引用)
Scala
的 ==
操作符和Java
的不同,Scala
的==
等同于equals
,而不是Java中对比引用。
Scala
中eq
操作符等同于Java中的==
。
new Person("Noel", "Welsh") eq (new Person("Noel", "Welsh"))
// res: Boolean = false
dave eq dave
// res: Boolean = true
伴生对象特性
伴生对象有一个和类构造函数一模一样参数列表的apply
方法。这样可以不使用new
关键字来创建对象。
Person("Dave", "Gurnell") == Person("Noel", "Welsh")
// res: Boolean = false
Person("Dave", "Gurnell") == Person("Dave", "Gurnell")
// res: Boolean = true
Case object
如果想定义一个没有初始化参数的case class,可以直接使用case object。并且拥有和case class一样的默认函数(equals
hashCode
toString
等)。
case object Citizen {
def firstName = "John"
def lastName = "Doe"
def name = firstName + " " + lastName
}
case object定义了一个类和对象,并且这个对象是这个类的唯一实例。
class Citizen { /* ... */ }
object Citizen extends Citizen { /* ... */ }
case object和case class拥有同样的功能特性。
模式匹配
以上,我们可以通过方法调用或者成员访问与对象进行交互,同样,我们可以通过另外一种方式--模式匹配。
模式匹配像是一个扩展的if
表达式,通过“形状”来辨识对象。
case class Person(firstName: String, lastName: String)
“形状”蕴含在构造函数里。
现在我们想找出星球大战中的反抗军成员。
object Stormtrooper {
def inspect(person: Person): String =
person match {
case Person("Luke", "Skywalker") => "Stop, rebel scum!"
case Person("Han", "Solo") => "Stop, rebel scum!"
case Person(first, _) => s"Move along, $first"
}
}
note: _
匹配所有值,并忽略它。
使用
Stormtrooper.inspect(Person("Noel", "Welsh"))
// res: String = Move along, Noel
Stormtrooper.inspect(Person("Han", "Solo"))
// res: String = Stop, rebel scum!
实现二叉树(int)
abstract class IntTree
case object EmptyTree extends IntTree
case class TreeNode(value: Int, left: IntTree, right: IntTree) extends IntTree
def contains(e: Int, t: IntTree): Boolean = t match {
case EmptyTree => false
case TreeNode(v, left, right) => if (v == e) true else contains(e, left) || contains(e, right)
}
def insert(e: Int, t: IntTree): Unit = t match {
???
}
scala> contains(1, TreeNode(2, TreeNode(1, EmptyTree, EmptyTree), EmptyTree))
// res0: Boolean = true
当然你也可以加入泛型以支持任何类型的元素。
abstract class BTree[A]
case object EmptyTree extends BTree
case class TreeNode[A](value: A, left: BTree[A], right: BTree[A]) extends BTree[A]
网友评论