相信每个scala程序员都有用过模式匹配。 在scala 中模式匹配也是非常强的。 下面我们来看看模式匹配的8个用法:
1. List Extractors:
下面看下代码实例:
val countingList = List(1,2,3,200)
// 我们可以提取这个list中的任意值
val mustHaveThree = countingList match {
case List(_,_,3,somethingElse) => s "this list contains 3, the forth is $somethingElse"
}
以上的模式匹配会匹配到一个含有4个元素的list, 其中我们并不关心前两个元素, 但是第三个元素必须是3, 第四个元素我们可以在interpolated string 中提取。
2. haskell-like prepending
我们同样可以提取以上list的头元素和尾元素:
val startsWithOne = countingList match {
case 1 :: someOtherElements => "the list starts with 1. the rest is $someOtherElements"
}
def processList(numbers: List[Int]): String = numbers match {
case Nil => ""
case h :: t => h + "" + processList(t)
}
3. List vararg pattern
在事例一中, 我们匹配了4个元素, 可如果我们不知道整个list有多少元素的话, 我们就可以使用 list vararg 模式:
val dontCareAboutTheRest = countingList match {
case List(_,2,_*) => "I only care that this list has 2 as second element"
}
_* 是一个非常重要的部分, 它代表了任意个数的元素。这中模式匹配会非常的灵活, 因为我们可以匹配任意个数的元素。
需要注意的是 _* 必须要在最后一个元素。 List(_,2,_*,55) 这种是错误的。
4. Other list infix patterns
我们之前匹配了第一个元素, 但是有时候我们想匹配最后一个元素, 这时候我们可以:
val mustEndWithMeaningOfLife = countingList match {
case List(1,2,_) :+ 120 => "the last element is 120"
}
val mustEndWithMeaningOfList2 = countingList match {
case List(1,_*) :+ 120 => "I do not care what coms before 120"
}
5. Type specifiers
我们不仅可以值匹配, 还可以进行类型匹配
def gimmeAValue(): Any = {...}
val gimmeTheType = gimmeAValue() match {
case _:String => "this method returns String"
case _:Int => "this method returns Int"
case _ => "this method returns something else"
}
try {...} catch {
case _:IOException => "IO failed"
case _:Exception => "we could have prevented that"
case _:RuntimeException => "something else crashed"
}
这种类型匹配会用到反射, 所以可能会有一些性能的影响。
6. Name binding
def requestMoreInfo(p: Person): String = { ... }
val bob = Person("Bob", 34, List("Inception", "The Departed"))
val bobsInfo = bob match {
case Person(name, age, movies) =>
s"$name's info: ${requestMoreInfo(Person(name, age, movies))}"
}
// 我们使用 p @ 来命名
val bobsInfo = bob match {
case p @ Person(name, _, _) => s"$name's info: ${requestMoreInfo(p)}"
}
val bobsInception = bob match {
case Person(name, _, movies @ List("Inception", _*)) =>
s"$name REALLY likes Inception, some other movies too: $movies"
}
7. Conditional guards
我们可以在pattern mattern中使用if 条件语句
val ordinal = gimmeANumber() match {
case 1 => "first"
case 2 => "second"
case 3 => "third"
case n if n % 10 == 1 => n + "st"
case n if n % 10 == 2 => n + "nd"
case n if n % 10 == 3 => n + "rd"
case n => n + "th"
}
8. Alternative patterns
如果有多个case 返回同样的结果, 我们可以使用 ‘|’ 来拼接这些case, 类似于 “或”
val myOptimalList = numbers match {
case List(1, _, _) | List (43, _*) => "I like this list"
case _ => "I don't like it"
}