聊聊 scala 的模式匹配

一. scala 模式匹配(pattern matching)

pattern matching 可以說是 scala 中十分強大的一個語言特性,當然這不是 scala 獨有的,但這不妨礙它成爲 scala 的語言的一大利器。

scala 的 pattern matching 是類似這樣的,

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

其中,變量 e 後面接一個 match 以及一個代碼塊,其中每個 case 對應一種可能回匹配的類型,如果匹配成功則執行 => 後面的代碼。

我們可以用一個具體一些的例子來看看模式匹配是怎麼工作的:

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,但其實還是有很大的不同的。

以java 的 switch 爲例,java 的 switch 僅僅會做一些基本類型的匹配,然後執行一些動作,並且是沒有返回值的。

而 scala 的 pattern matching match 則要強大得多,除了可以匹配數值,同時它還能匹配類型。

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 返回值是由第一個匹配的模式中的代碼塊決定的。

二. 爲什麼要用 pattern matching

看到這裏你會發現一個問題, pattern matching 不是和if else 差不多嗎?那爲什麼還要使用 pattern matching 呢?

首先我們需要明白,模式匹配其實本質上是提供一個方便的解構 (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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章