1. 概述
现代面向对象编程语言通常会提供一些抽象机制来表示简单、不可变的数据结构。在 Scala 中,这种机制就是 case class(样例类)。
本文将深入探讨 Scala 中的 case class,对比它与普通 class 的差异,并分析它所带来的优势。
2. Case Class
我们先从一个简单的 case class 定义开始:
case class CovidCountryStats(countryCode: String, deaths: Int, confirmedCases: Int)
✅ 默认情况下,所有构造参数都是 公共且不可变的(val)。虽然你可以将它们声明为 var
,但这并不是 case class 的设计初衷。
⚠️ 注意,这与普通 class 的默认行为不同 —— 普通 class 的构造参数默认是私有的。
Scala 的 case class 在设计上与 Kotlin 的 data class 非常相似,Java 14 引入的 records 也有异曲同工之妙。
接下来,我们来看看 case class 提供的几大特性。
2.1. 简洁的实例化语法
创建 case class 实例非常简洁:
val covidPL = CovidCountryStats("PL", 776, 15366)
注意,我们没有使用 new
关键字。这是因为 case class 会自动生成一个 apply
方法,由编译器自动提供。
如果 case class 嵌套使用,这种简洁语法也能让复杂对象的创建变得非常直观!
2.2. 模式匹配支持
case class 最强大的特性之一就是支持模式匹配(Pattern Matching),可以优雅地解构对象:
covidPL match {
case CovidCountryStats("PL", x, y) => println("Death rate for Poland is " + x.toFloat / y.toFloat)
...
case _ => println("Unknown country")
}
这之所以可行,是因为 case class 会自动生成一个伴生对象(companion object),其中包含:
apply
方法(用于实例化)unapply
方法(用于提取器,支持模式匹配)
2.3. 自动生成的方法
和 Kotlin 的 data class 一样,Scala 的 case class 会自动实现以下方法:
equals
hashCode
toString
并且这些方法都是基于字段内容自动生成的,非常实用。
2.4. 结构相等性
case class 实例默认是 结构相等 的,而不是引用相等:
assert(CovidCountryStats("PL", 776, 15366) == CovidCountryStats("PL", 776, 15366))
✅ 上述断言会通过,因为两个对象的内容完全一致。
❌ 如果去掉 case
关键字,变成普通 class,默认的 ==
是基于引用的,结果会是 false
。
2.5. Product 特质
case class 默认继承了 Product
特质,因此具备以下方法:
productElement(n: Int): Any
:获取第 n 个参数productArity: Int
:获取参数个数productIterator: Iterator[Any]
:迭代所有参数
⚠️ 由于 Product
的限制,case class 最多只能有 22 个参数。
2.6. 浅拷贝的 copy 方法
case class 自动提供 copy
方法,用于创建新的实例(浅拷贝):
val covidUA = covidPL.copy(countryCode = "UA")
⚠️ 注意:copy
只做浅拷贝,嵌套对象不会被深拷贝。
2.7. tupled 方法
case class 的伴生对象还提供了一个 tupled
方法,可以从元组创建对象:
val tuple = ("PL", 776, 15366)
val covidPL = (CovidCountryStats.apply _).tupled(tuple)
这个特性在函数式编程中尤其有用。
2.8. 其他注意事项
在使用 case class 时还需注意以下限制:
- ❌ case class 不能继承另一个 case class
- ✅ case class 默认实现了
Serializable
接口
3. 总结
在这篇文章中,我们详细介绍了 Scala 中的 case class,对比了它与普通 class 的区别。
case class 的优势在于:
- ✅ 极大地减少了样板代码
- ✅ 支持模式匹配
- ✅ 自动生成常用方法(equals、hashCode、toString)
- ✅ 结构相等性
- ✅ 支持 copy 和 tupled 等实用方法
⚠️ 但也要注意,这些便利的背后是编译器自动生成的约 20 个方法,可能会略微增加字节码体积。
💡 最后,推荐使用 scalac -print
命令查看 case class 编译后的实际代码,有助于深入理解其底层机制。
如需获取文中代码示例,可访问:GitHub 仓库