如何使用Scala的模式匹配

153 阅读4分钟

概述

在这篇文章中,我们将展示Scala的一个功能特性,即模式匹配

如果你过去使用过Java或.NET,那么乍一看,它可能与switch语句相似。但是,Scala的模式匹配要强大得多!

模式匹配的不同方式

1.模式匹配:一个非常基本的例子

假设你想测试一个叫做donutType的变量。如果它的值是Glazed Donut,你会打印Very Tasty。另一方面,如果它的值是Plain Donut,那么你将打印Tasty


val donutType = "Glazed Donut"
donutType match {
  case "Glazed Donut" => println("Very tasty")
  case "Plain Donut" => println("Tasty")
}

当你在IntelliJ中运行你的Scala应用程序时,你应该看到以下输出。


Very tasty

注意

  • 你应该注意到,与Java或**.NET不同的是,这里没有break**语句!
  • 我敢肯定,你一定看到过你的那份bug,这些bug来自于有人忘了使用break语句的事实。在Java或**.NET中,这将允许逻辑下降**到下一个case语句。
  • 这也要感谢Scala,因为它的编译器足够聪明,可以防止落空,因此没有必要使用break子。

2.模式匹配并返回结果

如果你不想简单地打印出甜甜圈的不同口味等级,而是想把它存储在一个变量中,那该怎么办?


val tasteLevel = donutType match {
  case "Glazed Donut" => "Very tasty"
  case "Plain Donut" => "Tasty"
}
println(s"Taste level of $donutType = $tasteLevel")

当你在IntelliJ中运行你的Scala应用程序时,你应该看到以下输出。


Taste level of Glazed Donut = Very tasty

注意

  • 注意,你不必像在Java或**.NET中那样使用返回**关键字。
  • 相反,最后一个表达式将是返回给调用者的那个。在我们学习函数的教程时,我们会看到更多的返回类型。

3.使用通配符进行模式匹配

正如你在第1步中所学到的,没有必要使用任何断句,因为在使用模式匹配时没有落空。但是,如果你需要提供一个默认的情况呢?


println("\nStep 3: Pattern matching using the wildcard operator")
val tasteLevel2 = donutType match {
  case "Glazed Donut" => "Very tasty"
  case "Plain Donut" => "Tasty"
  case _ => "Tasty"
}
println(s"Taste level of $donutType = $tasteLevel2")

当你在IntelliJ中运行你的Scala应用程序时,你应该看到以下输出。


Step 3: Pattern matching using the wildcard operator
Taste level of Glazed Donut = Very tasty

注意

  • 如果你来自纯面向对象的编程背景,使用通配符运算符几乎肯定会感到不自然。
  • 别担心,在接下来的教程中,我们会看到更多通配符操作符的例子!

4.在同一条件下的两个或多个项目的模式匹配

在我们的例子中,我们将釉面甜甜圈项目标记为非常美味。如果一个草莓甜甜圈也是非常美味的呢。这种行为似乎类似于一个OR表达式,你可以使用管道。


val tasteLevel3 = donutType match {
  case "Glazed Donut" | "Strawberry Donut" => "Very tasty"
  case "Plain Donut" => "Tasty"
  case _ => "Tasty"
}
println(s"Taste level of $donutType = $tasteLevel3")

当你在IntelliJ中运行你的Scala应用程序时,你应该看到以下输出。


Taste level of Glazed Donut = Very tasty

5.模式匹配和在case子句中使用if表达式

与步骤4类似,你可以通过在case语句中添加if来模拟OR子句。


val tasteLevel4 = donutType match {
  case donut if (donut.contains("Glazed") || donut.contains("Strawberry")) => "Very tasty"
  case "Plain Donut"  => "Tasty"
  case _  => "Tasty"
}
println(s"Taste level of $donutType = $tasteLevel4")

当你在IntelliJ中运行你的Scala应用程序时,你应该看到以下输出。


Taste level of Glazed Donut = Very tasty

6.按类型进行模式匹配

到目前为止,我们一直在处理一些变量的值。如果你想对变量的类型进行模式匹配呢?

让我们明确声明一个变量的类型为Any,以保存一个甜甜圈的价格。Scala编译器会推断出priceOfDonut的类型为Double

让我们用一些例子来证明吧!


println("\nStep 6: Pattern matching by types")
val priceOfDonut: Any = 2.50
val priceType = priceOfDonut match {
  case price: Int => "Int"
  case price: Double => "Double"
  case price: Float => "Float"
  case price: String => "String"
  case price: Boolean => "Boolean"
  case price: Char => "Char"
  case price: Long => "Long"
}
println(s"Donut price type = $priceType")

当你在IntelliJ中运行你的Scala应用程序时,你应该看到以下输出。


Step 6: Pattern matching by types
Donut price type = Double

注意

  • 如果你来自JavaNET,你可以认为Any类型类似于Object类。
  • 换句话说,Any 是Scala类型层次结构的根。

总结

在这篇文章中,我们讨论了基本的模式匹配、将结果返回给调用者、通配符操作、同一条件下的两个或多个项目、使用if表达式以及使用类型。