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的人可能非常熟悉这种处理列表的方式。

scala模式匹配什么意思(8种Scala模式匹配技巧)(1)

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 => "" }

最后,没什么好说的,大家今天都过得愉快吧。

,