聊聊 scala 的模式匹配

一. scala 模式匹配(pattern matching)

pattern matching 能够说是 scala 中十分强大的一个语言特性,固然这不是 scala 独有的,但这不妨碍它成为 scala 的语言的一大利器。html

scala 的 pattern matching 是相似这样的,java

e match {
  case Pattern1 => do Something
  case Pattern2 if-clause => do others
  ...
}

其中,变量 e 后面接一个 match 以及一个代码块,其中每一个 case 对应一种可能回匹配的类型,若是匹配成功则执行 => 后面的代码。web

咱们能够用一个具体一些的例子来看看模式匹配是怎么工做的:数据结构

case class Player(name: String, score: Int)
def printMessage(player: Player) = player match {
  case Player(_, score) if score > 100000 =>
    println("Get a job, dude!")
  case Player(name, _) =>
    println("Hey, $name, nice to see you again!")
}

看起来有点相似于其余语言的 switch,但其实仍是有很大的不一样的。app

以java 的 switch 为例,java 的 switch 仅仅会作一些基本类型的匹配,而后执行一些动做,而且是没有返回值的。ide

而 scala 的 pattern matching match 则要强大得多,除了能够匹配数值,同时它还能匹配类型。svg

def parseArgument(arg: String) = arg match {
    //匹配值
    case "-h" | "--help" => displayHelp
    case "-v" | "--version" => displayVerion
    case whatever => unknownArgument(whatever)
}
def f(x: Any): String = x match {
    //匹配类型
    case i:Int => "integer: " + i
    case _:Double => "a double"
    case s:String => "I want to say " + s
}

同时 pattern matching 是有返回值的,好比上面的 match ,它返回的就是一个 Unit。咱们也能够修改上面的代码让它返回一个字符串:测试

case class Player(name: String, score: Int)
def message(player: Player) = player match {
  case Player(_, score) if score > 100000 =>
    "Get a job, dude!"
  case Player(name, _) =>
    "Hey, $name, nice to see you again!"
}

值得一提的是, pattern matching 返回值是由第一个匹配的模式中的代码块决定的。ui

二. 为何要用 pattern matching

看到这里你会发现一个问题, pattern matching 不是和if else 差很少吗?那为何还要使用 pattern matching 呢?scala

首先咱们须要明白,模式匹配其实本质上是提供一个方便的解构 (Destructuring) 数据结构的方式,以 scala 为例, pattern matching 其实用到了 scala 中提取器的功能, 提取器其实就是类中的 unapply () 方法。

trait User {
  def name: String
}
class FreeUser(val name: String) extends User
object FreeUser {
  //提取器
  def unapply(user: FreeUser): Option[String] = Some(user.name)
}
val user: User = new FreeUser("Daniel")
  user match {
    case FreeUser(name) => println("it match here" + name)
    case _ => println("not me")
  }

明白了模式匹配的本质你就会直到,其实 if else 只是 pattern matching 中的一个典型的用法,但并不是它的所有。

同时, pattern matching 容许你解耦两个并不真正属于彼此的东西,也使得你的代码更易于测试。好比上面的 match 部分的代码咱们能够写成下面这样:

val user: User = new FreeUser("Daniel")
  //将返回结果存在一个常量中
  val message = user match {
    case FreeUser(name) => "it match here" + name
    case _ => "not me"
  }
  //能够随意使用该常量,实现解耦
  println(message)

这样会赋予代码更多的灵活性,同时也更加方便作进一步操做。

而以可读性的角度来讲,使用一大堆的 if else 代码无疑是比较难看的,而若是使用 pattern matching 的话,代码会简洁清晰不少,而简洁的代码则会更容易阅读。

参考文章:

https://doc.yonyoucloud.com/doc/guides-to-scala-book/chp3-pattern-everywhere.html

https://www.zhihu.com/question/30354775