目录
在 Scala 中,模式匹配是一种强大的语言特性,它可以用于匹配各种类型的值,包括基本类型、集合、对象等,从而实现分支逻辑、类型转换、提取数据等操作。
1 基本用法
val a = 3
val b = 2
val operator = "&"
val result = operator match {
case "+" => a + b
case "-" => a - b
case "*" => a * b
case "/" => a.toDouble / b
case _ => "illegal"
}
println(result)// illegal
2 模式守卫
def abs(x: Int) = x match {
case i: Int if i >= 0 => i
case j: Int if j < 0 => -j
case _ => "type illegal"
}
println(abs(-1))
3 模式匹配类型
3.1 匹配常量
匹配常量是模式匹配的一种形式,可以用于匹配特定的常量值。
val x = 1
x match {
case 1 => println("x is one")
case 2 => println("x is two")
case _ => println("x is neither one nor two")
}
3.2 匹配类型
Scala的模式匹配功能还可以用于匹配类型。这意味着您可以根据表达式的类型来执行不同的代码块。
def process(input: Any): Unit = {
input match {
case x: Int => println(s"$x is an integer")
case s: String => println(s"$s is a string")
case d: Double => println(s"$d is a double")
case _ => println("Unknown type")
}
}
process(42) // 42 is an integer
process("hello") // hello is a string
process(3.14) // 3.14 is a double
process(true) // Unknown type
3.3 匹配数组
val arr = Array("apple", "banana", "orange")
arr match {
case Array() => println("empty array")
case Array(x) => println(s"one-element array: $x")
case Array("apple", "banana", _*) => println("starts with apple and banana")
case _ => println("something else")
}
3.4 匹配列表
val lst = List(1, 2, 3)
lst match {
case Nil => println("empty list")
case x :: Nil => println(s"one-element list: $x")
case 1 :: 2 :: 3 :: _ => println("starts with 1, 2, 3")
case _ => println("something else")
}
3.5 匹配元组
val tup = (1, "hello", 3.14)
tup match {
case (1, _, _) => println("starts with 1")
case (_, "hello", _) => println("second element is hello")
case (_, _, d) if d > 0.0 => println("third element is positive")
case _ => println("something else")
}
4 匹配对象及样例类
4.1 匹配对象
case class Person(name: String, age: Int) {}
object TestMatch extends App {
val alice = Person("Alice", 25)
val bob = Person("Bob", 30)
def process(person: Person): Unit = {
person match {
case Person("Alice", _) => println("Hi Alice!")
case Person("Bob", age) if age > 25 => println("Hi Bob, you are over 25!")
case Person(name, _) => println(s"Hi $name, how are you?")
case _ => println("Unknown person")
}
}
process(alice) // Hi Alice!
process(bob) // Hi Bob, you are over 25!
process(Person("Charlie", 35)) // Hi Charlie, how are you?
}
4.2 样例类
在Scala中,样例类(case class)是一种特殊的类,它具有以下特点:
- 自动生成构造函数:样例类的构造函数是自动生成的,不需要手动编写。
- 自动生成
apply
方法:样例类自动带有一个apply
方法,可以用于创建该类的对象,而无需使用new
关键字。 - 自动生成
unapply
方法:样例类自动带有一个unapply
方法,可以用于提取该类的属性值。 - 自动生成
equals
和hashCode
方法:样例类自动实现了equals
和hashCode
方法,可以用于比较两个对象是否相等。 - 自动生成
toString
方法:样例类自动实现了toString
方法,可以用于打印该类的对象。
样例类通常用于表示不可变的数据,例如,一张纸牌、一条消息或一个人的信息等。它们提供了一种简洁而直观的方式来表示这些数据,并且可以方便地进行模式匹配。
以下是一个样例类的示例:
case class Person(name: String, age: Int)
5 变量声明中的模式匹配
val (x, y) = (1, 2)
可以使用模式匹配来解构一个元组,或者匹配一个列表的头和尾。下面是一个例子:
val (head :: tail) = List(1, 2, 3)
// 1
// List(2, 3)
6 for 表达式中的模式匹配
在 Scala 的
for
表达式中,可以使用模式匹配来解构集合中的元素。这种方式可以让我们在遍历集合的同时,对集合中的元素进行匹配和赋值。
val list = List((1, "one"), (2, "two"), (3, "three"))
for ((num, word) <- list) {
println(s"$num is written as $word")
}
7 偏函数中的模式匹配(了解)
7.1 偏函数概念
偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。例如该偏函数的输入类型为List[Int],而我们需要的是第一个元素是 0 的集合,这就是通过模式匹配实现的。
7.2 偏函数定义
// 该偏函数的功能是返回输入的List 集合的第二个元素
val second: PartialFunction[List[Int], Option[Int]] = {
case x :: y :: _ => Some(y)
}
7.3 偏函数原理
上述代码会被 scala 编译器翻译成以下代码,与普通函数相比,只是多了一个用于参数检查的函数——isDefinedAt,其返回值类型为 Boolean
val second = new PartialFunction[List[Int], Option[Int]] {
//检查输入参数是否合格
override def isDefinedAt(list: List[Int]): Boolean = list match
{
case x :: y :: _ => true case _ => false
}
//执行函数逻辑
override def apply(list: List[Int]): Option[Int] = list match
{
case x :: y :: _ => Some(y)
}
}
7.4 偏函数使用
偏函数不能像 second(List(1,2,3))这样直接使用,因为这样会直接调用 apply 方法,而应该调用 applyOrElse 方法,如下
second.applyOrElse(List(1,2,3), (_: List[Int]) => None)
applyOrElse 方法的逻辑为
if (ifDefinedAt(list))
apply(list)
else
default
如果输入参数满足条件,即 isDefinedAt 返回 true,则执行 apply 方法,否则执行 defalut 方法,default 方法为参数不满足要求的处理逻辑。
例如
将该List(1,2,3,4,5,6,"test")中的 Int 类型的元素加一,并去掉字符串。
list.collect { case x: Int => x + 1 }.foreach(println)