前言
大概介绍一下 scala中强大的模式匹配功能
最简单的例子
val bools = Seq(true,false) bools.foreach { case true => println("it's ture") case false => println("it's false") }
就是一个最简单的匹配。
类型匹配和值匹配
for { x <- Seq(1,2,3.1,"one","two",true) } { val s = x match { case 1 => "it's one" case _ :Int | _:Double => s"it's a number $x" case "one" => "it's one" case _:String => s"other string $x" case _ => s"unexpected value $x" } println(s) }
基本能说明问题了
seq匹配
val nonEmptySeq = Seq (1,2,5,6,8) val emptySeq = Seq.empty[Int] def seqToString[T](seq:Seq[T]):String = { seq match { case Nil => "Nil" case head +: tail => s"$head +: ${seqToString(tail)}" } } println(seqToString(nonEmptySeq)) println(seqToString(emptySeq))
其中的 +: 很有趣。 其实我们可以通过 1 :+ 2 :+3 :+ Nil 来构建一个 (1,2,3,Nil) 的序列。scala为了保证逆操作也可以通过 +: 来实现,所以特意写了一个单例
object +: { def unapply[T,Coll <: SeqLike[T, Coll]]( t: Coll with SeqLike[T, Coll]): Option[(T, Coll)] = if(t.isEmpty) None else Some(t.head -> t.tail) }
对于 unapply 后续再说,从上面的代码可以看出 :+ 其实就是一个单例。 在case 中做提取的时候,其实调用的是
case +:(head,tail) => s"$head +: ${seqToString(tail)}"
scala 通过中缀表达式,那么 就可以使用
case head +: tail => s"$head +: ${seqToString(tail)}"
顿时有一种大道至简的感觉。
case class 匹配
case class Address(street:String,city:String,coutry:String) case class Person(name:String,age:Int,address: Address) val alice = Person("alice",21,Address("1 street","beijing","china")) val bill = Person("bill",29,Address("2 street","hangzhou","china")) Seq(alice,bill).foreach{ case Person("alice",_ ,Address(_,city,_)) => println(s"hello alice .you are from $city") case Person("bill",_,_) => println("hello bill") case _ => println("who are you") }
直接看代码。 case class的匹配在 akka中用户非常大,可以让代码非常优雅。可以说就算从来没碰过scala人都知道这个匹配的意思。
unapply
class Person( val name:String,val age:Int) object Person { def apply(name: String, age: Int): Person = new Person(name, age) def unapply(person: Person): Option[(String, Int)] = Some((person.name,person.age)) } val person = Person("bill",29) person match { case Person(_,29) => println("you are 29") case _ => "who are you" }
对于scala来说,希望能支持构造(apply)和解构(unapply)的标准语法。之前提到的case class,其实大体的作用就是如上面所说,自动帮我们写了一个unapply的方法。对于的入参就是对象本身,出参是一个Option(scala2.11.1以后放松了限制,只需要返回的对象实现了isEmpty 和 get方法就ok). 其中apply 和 unapply互为逆操作。
正则表达式的匹配
val TtidRE = "(\\d+)@(.+)_(.+)_(\\d|.+)".r val ttid = "201200@taobao_iphone_2.1.0" ttid match { case TtidRE(channel,client,platform,version) => println(s"channel=$channel,client=$client,platform=$platform,version=$version") case _ => println("not match") }
如此优雅的代码!