1.列表提取器
列表可以通过多种功能强大的模式匹配来解构。首先是要构建清单。
val countingList = List(1,2,3,42)
使用类似于案例类构造函数的模式从此列表中提取任何元素:
val mustHaveThree = countingList match {
case List(_, _, 3, somethingElse) => s“ 有一个包含3作为第三个元素的列表,之后我发现$ somethingElse”
}
此模式将一个列表与四个元素完全匹配,其中我们不关心前两个元素。第三个必须恰好是3就行了,第四个可以是任何东西,之所以将其命名为somethingElse,是因为可以在s插值字符串中重用它。
2. Haskell-Like前置
如果认为清单与以前相同,则可以按照下面的提取清单的开头和结尾:
val startsWithOne = countingList match {
case 1 :: someOtherElements => “此列表以一个开头,其余为$ someOtherElements”
}
不要问这怎么可能。即将就是主题了。前置模式在处理列表的代码中非常有用,别忘记啦,但是当事先不知道列表是否为空时,可以这样写:
def processList(numbers: List[Int]): String = numbers match {
case Nil => ""
case h :: t => h " " processList(t)
}
熟悉Haskell的人可能非常熟悉这种处理列表的方式。
3.列出Vararg模式
上面显示的第一个模式只能将列表限制为一定数量的元素。如果不知道元素的数量又咋办?
val dontCareAboutTheRest = countingList match {
case List(_, 2, _*) => "只关心此列表具有2,作为第二个元素"
}
_ _*是重要的位,表示“任何数量的附加参数”。这种模式更加灵活,几乎无数个列表可以匹配该模式,而不是我们之前使用的4元素列表模式。唯一_*要注意的是它必须是模式中的最后一位。换句话说,该情况下,List(_, 2, _*, 55),将无法被翻译。
4.其他列表中缀模式
当我们可以测试列表的开头,甚至测试列表中的元素时,它很有用。但我们要测试列表的最后一个元素呢?
val mustEndWithMeaningOfLife = countingList match {
case List(1,2,_) : 42 =>
}
: 是追加操作符,这很像::从视图模式匹配的点。也可以使用 :prepend运算符,但我更喜欢::
val mustEndWithMeaningOfLife2 = countingList match {
case List(1, _*) : 42 =>
}
5.类型说明符
有时,实际上并不关心要匹配的值,而只关心它们的类型。
def gimmeAValue(): Any = { ... }
val gimmeTheType = gimmeAValue() match {
case _: String =>
case _: Int =>
case _ =>
}
该:String位是重要的组成部分。它允许案例仅匹配那些符合该类型的模式。当捕获异常时,特别有用。
try {
...
} catch {
case _: IOException =>
case _: Exception =>
case _: RuntimeException =>
}
类型防护的缺点是它们基于反射。别忘记了,这点真的容易犯错。
6.名称绑定
我看过以下模式的次数超出了我的预期:
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的信息:$ {requestMoreInfo(Person(姓名,年龄,电影))}”
}
我们解构一个案例类只是为了用相同的数据重新实例化它,以便以后使用。如果不关心case类中的任何字段,但是,如果关心的不是全部和整个实例,又该咋办呢?
val bobsInfo = bob match {
case p @ Person(name, _, _) => s“ $ name的信息:$ {requestMoreInfo(p)}”
}
答:命名要匹配的模式,以便以后可以重用。甚至可以命名子模式:
val bobsInception = xiaoming match {
case Person(name, _, movies @ List("Inception", _*)) => s“ $ name真的很喜欢Inception,其他电影也很喜欢:$ movies”
}
7. Conditional Guards
如果像我一样,可能至少尝试过一次模式匹配满足条件的内容,由于只知道“任何”和“恒定”模式,因此放弃了模式匹配,而是使用了链式if-elses,这也是经常的。
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"
}
如上所示,if防护直接位于模式中。另请注意,该条件没有括号。
8.替代模式
如果针对多个模式返回相同的表达式,则无需c v去复制相同的代码。
val myOptimalList = numbers match {
case List(1, _, _) => “我喜欢这个列表”
case List(43, _*) => “我喜欢这个列表”
case _ => “我不喜欢这个列表”
}
也可以将返回相同表达式的模式组合为一个模式:
val myOptimalList = numbers match {
case List(1, _, _) | List (43, _*) => “我喜欢这个列表”
case _ => “我不喜欢这个列表”
}
这种模式的唯一缺点是不能绑定任何名称,因为无法确保这些值在右侧可用。
在许多情况下,例如,想处理多种异常时,此模式在实践中很有用:
try {
...
} catch {
case _: RuntimeException | _: IOException => ""
}
最后,没什么好说的,大家今天都过得愉快吧。
,