样例类 #

一、样例类基础 #

1.1 定义样例类 #

使用 case class 关键字:

scala
case class Person(name: String, age: Int)

val person = Person("Alice", 25)
println(person.name)
println(person.age)

1.2 自动生成的特性 #

case class 自动生成:

  • apply 方法(无需 new)
  • toString 方法
  • equalshashCode 方法
  • copy 方法
  • unapply 方法(模式匹配)

1.3 与普通类对比 #

scala
class Person1(val name: String, val age: Int)

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

val p1 = Person1("Alice", 25)
val p2 = Person2("Alice", 25)

println(p1)
println(p2)

二、样例类特性 #

2.1 自动生成 apply #

scala
case class Person(name: String, age: Int)

val person = Person("Alice", 25)

2.2 自动生成 toString #

scala
case class Person(name: String, age: Int)

val person = Person("Alice", 25)
println(person)

2.3 自动生成 equals 和 hashCode #

scala
case class Person(name: String, age: Int)

val p1 = Person("Alice", 25)
val p2 = Person("Alice", 25)
val p3 = Person("Bob", 30)

println(p1 == p2)
println(p1 == p3)

val set = Set(p1, p2, p3)
println(set.size)

2.4 copy 方法 #

scala
case class Person(name: String, age: Int)

val p1 = Person("Alice", 25)
val p2 = p1.copy(age = 26)
val p3 = p1.copy(name = "Bob")

println(p1)
println(p2)
println(p3)

2.5 模式匹配 #

scala
case class Person(name: String, age: Int)

def describe(person: Person): String = person match
  case Person("Alice", _) => "It's Alice"
  case Person(name, age) if age < 18 => s"$name is a minor"
  case Person(name, age) => s"$name is $age years old"

println(describe(Person("Alice", 25)))
println(describe(Person("Bob", 15)))
println(describe(Person("Charlie", 30)))

三、不可变性 #

3.1 默认不可变 #

case class 的参数默认是 val:

scala
case class Person(name: String, age: Int)

val person = Person("Alice", 25)

3.2 使用 copy 修改 #

scala
case class Person(name: String, age: Int)

val p1 = Person("Alice", 25)
val p2 = p1.copy(age = 26)

3.3 可变字段(不推荐) #

scala
case class Counter(var count: Int)

val counter = Counter(0)
counter.count += 1
println(counter.count)

四、模式匹配详解 #

4.1 基本匹配 #

scala
case class Point(x: Int, y: Int)

val point = Point(10, 20)

val result = point match
  case Point(0, 0) => "Origin"
  case Point(x, 0) => s"On x-axis at $x"
  case Point(0, y) => s"On y-axis at $y"
  case Point(x, y) => s"Point at ($x, $y)"

println(result)

4.2 守卫条件 #

scala
case class Person(name: String, age: Int)

def categorize(person: Person): String = person match
  case Person(_, age) if age < 0 => "Invalid age"
  case Person(_, age) if age < 13 => "Child"
  case Person(_, age) if age < 20 => "Teenager"
  case Person(_, age) if age < 65 => "Adult"
  case _ => "Senior"

4.3 嵌套匹配 #

scala
case class Address(city: String, country: String)
case class Person(name: String, address: Address)

val person = Person("Alice", Address("Beijing", "China"))

val result = person match
  case Person(name, Address("Beijing", _)) => s"$name lives in Beijing"
  case Person(name, Address(_, "China")) => s"$name lives in China"
  case Person(name, _) => s"$name lives somewhere"

4.4 集合中的模式匹配 #

scala
case class Person(name: String, age: Int)

val people = List(
  Person("Alice", 25),
  Person("Bob", 17),
  Person("Charlie", 30)
)

val adults = people.collect {
  case p @ Person(_, age) if age >= 18 => p
}

val names = people.map { case Person(name, _) => name }

五、样例对象 #

5.1 定义样例对象 #

scala
case object Empty

case class NonEmpty(head: Int, tail: List[Int])

def describe(list: List[Int]): String = list match
  case Nil => Empty.toString
  case head :: tail => NonEmpty(head, tail).toString

5.2 作为消息 #

scala
sealed trait Message
case object Start extends Message
case object Stop extends Message
case class Data(value: Int) extends Message

def handle(message: Message): String = message match
  case Start => "Starting..."
  case Stop => "Stopping..."
  case Data(value) => s"Received data: $value"

5.3 作为枚举替代 #

scala
sealed trait Direction
case object North extends Direction
case object South extends Direction
case object East extends Direction
case object West extends Direction

def turn(direction: Direction): String = direction match
  case North => "Going North"
  case South => "Going South"
  case East => "Going East"
  case West => "Going West"

六、Sealed 特质与样例类 #

6.1 定义 Sealed 层次 #

scala
sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(width: Double, height: Double) extends Shape
case class Triangle(a: Double, b: Double, c: Double) extends Shape

6.2 穷尽性检查 #

scala
def area(shape: Shape): Double = shape match
  case Circle(r) => math.Pi * r * r
  case Rectangle(w, h) => w * h
  case Triangle(a, b, c) =>
    val s = (a + b + c) / 2
    math.sqrt(s * (s - a) * (s - b) * (s - c))

6.3 实用示例 #

scala
sealed trait Result[+T]
case class Success[T](value: T) extends Result[T]
case class Failure(message: String) extends Result[Nothing]

def divide(a: Int, b: Int): Result[Int] =
  if b == 0 then Failure("Division by zero")
  else Success(a / b)

def handle(result: Result[Int]): String = result match
  case Success(value) => s"Result: $value"
  case Failure(msg) => s"Error: $msg"

七、实战示例 #

7.1 表达式求值器 #

scala
sealed trait Expr
case class Number(value: Int) extends Expr
case class Add(left: Expr, right: Expr) extends Expr
case class Subtract(left: Expr, right: Expr) extends Expr
case class Multiply(left: Expr, right: Expr) extends Expr

def evaluate(expr: Expr): Int = expr match
  case Number(v) => v
  case Add(l, r) => evaluate(l) + evaluate(r)
  case Subtract(l, r) => evaluate(l) - evaluate(r)
  case Multiply(l, r) => evaluate(l) * evaluate(r)

val expr = Add(Number(1), Multiply(Number(2), Number(3)))
println(evaluate(expr))

7.2 JSON 解析 #

scala
sealed trait Json
case class JsonString(value: String) extends Json
case class JsonNumber(value: Double) extends Json
case class JsonBoolean(value: Boolean) extends Json
case class JsonArray(values: List[Json]) extends Json
case class JsonObject(fields: Map[String, Json]) extends Json
case object JsonNull extends Json

def stringify(json: Json): String = json match
  case JsonString(s) => s""""$s""""
  case JsonNumber(n) => n.toString
  case JsonBoolean(b) => b.toString
  case JsonArray(arr) => arr.map(stringify).mkString("[", ", ", "]")
  case JsonObject(obj) => obj.map { case (k, v) => s""""$k": ${stringify(v)}""" }
    .mkString("{", ", ", "}")
  case JsonNull => "null"

7.3 状态机 #

scala
sealed trait State
case object Idle extends State
case class Processing(progress: Int) extends State
case class Completed(result: String) extends State
case class Failed(error: String) extends State

def transition(current: State, event: String): State = (current, event) match
  case (Idle, "start") => Processing(0)
  case (Processing(p), "progress") if p < 100 => Processing(p + 10)
  case (Processing(100), "complete") => Completed("Done")
  case (Processing(_), "fail") => Failed("Error occurred")
  case (Completed(_) | Failed(_), "reset") => Idle
  case _ => current

八、样例类最佳实践 #

8.1 用于数据建模 #

scala
case class User(
  id: Long,
  name: String,
  email: String,
  createdAt: java.time.Instant
)

8.2 与 Sealed 结合 #

scala
sealed trait PaymentMethod
case class CreditCard(number: String, expiry: String) extends PaymentMethod
case class BankAccount(accountNumber: String, routingNumber: String) extends PaymentMethod
case object Cash extends PaymentMethod

8.3 保持不可变 #

scala
case class Counter(value: Int):
  def increment: Counter = copy(value = value + 1)
  def decrement: Counter = copy(value = value - 1)

val c1 = Counter(0)
val c2 = c1.increment
val c3 = c2.increment

九、总结 #

case class 自动生成 #

方法 说明
apply 无需 new 创建实例
toString 格式化输出
equals 值比较
hashCode 哈希计算
copy 复制修改
unapply 模式匹配

使用场景 #

场景 说明
数据模型 表示数据实体
消息传递 Actor 消息
模式匹配 结构化匹配
不可变数据 函数式编程

下一步,让我们学习 对象与伴生对象

最后更新:2026-03-27