Scala学习日志(二)——深入模式匹配(一)

时间:2022-01-24 05:45:21

码字不易,转发请注明出处:http://blog.csdn.net/qq_28945021/article/details/51984620

摘要

Scala模式匹配咋一看和Java中的Switch语句很相似,然而在Java中,只能匹配简单的数据类型和表达式。Scala模式匹配则更加强大:可以使用类型、通配符、序列、正则表达式。甚至可以深入获取对象的状态。本文主要以代码的形式,由简到繁的深入Scala模式匹配。

1.简单匹配

简单匹配和java中的switch一致,这里就不赘述。

//一个简单的例子:通过匹配Boolean值来模拟掷硬币
val flags=Seq(true,false)
for(flag <- flags){
flag match {
case true => println("Got heads")
//如果注释这行,会报错,因为无法匹配未case的值
case false => println("Got tails")
}
}
/*结果:
Got heads
Got tails
*/

2.match中的值、变量和类型

前面的简单匹配类似java中的switch,只是匹配单一数据类型的值。接下来我们使用Seq[Any]类型的集合来演示各种各样的match语句。注释写得十分详细,我这里就不做过多解释。

//以下例子可以匹配特定的某个值,也能匹配特定类型的值,
//同时展示了default语句的写法来匹配任意输入值
//注意:由于匹配是顺序进行的,所以具体的子句必须在宽泛的句子之前,
//否则具体的不会被匹配到
for{
//由于序列元素包含不同类型,因此序列的类型为Seq[Any]
x <- Seq(1,2,2.7,"one","two",'four)
}{
var str = x match { //x的类型为Any
case 1 => "int 1" //如果x为1时匹配
case i:Int => "other int:"+i //匹配除1以外的任意数值,将x的值安全地转为Int,并赋值给i
case d:Double => "a double:"+x //匹配所有Double类型,x的值被赋给Double型变量d
case "one" => "string one" //匹配字符串"one"
case s:String => "other string:"+s
//匹配除"one"以外的任意字符串,x的值被赋给String型变量s


case unexpected => "unexpected value" + unexpected
//匹配其他任意输入,x的值被赋给了unexpected这个变量。
//由于未给出任何类型说明,unexpected的类型被推断为Any,
// 起到了default语句的功能
}
println(str)
/*输出结果
int 1
other int:2
a double:2.7
string one
other string:two
unexpected value'four
*/
}

上面生成变量是为了让大家理解的简单些,事实上我们根本不用生成新的变量,因为我们已经有x可以使用了。我们可以使用占位符_来代替变量。

//如果愿意可以使用占位符_替换变量,在句子中使用x便好了
for{
//由于序列元素包含不同类型,因此序列的类型为Seq[Any]
x <- Seq(1,2,2.7,"one","two",'four)
}{
var str = x match {
case 1 => "int 1"
case _:Int => "other int:"+x
case _:Double => "a double:"+x
case "one" => "string one"
case _:String => "other string:"+x
case _ => "unexpected value" + x
}
println(str)
}

Scala的case语句还支持“或”逻辑,当匹配的操作相同时,为了避免代码的冗余,就可以使用 | 运算符:

for {
x <- Seq(1, 2, 2.7, "one", "two", 'four)
}{
var str = x match {
case 1 => "int 1"
case _:Int | _:Double=> "other number:"+x //注意:使用了|
case "one" => "string one"
case _:String => "other string:"+x
case _ => "unexpected value" + x
}
println(str)
}

3.序列的匹配

在使用序列的匹配的时候,由衷的感慨scala真是一门优雅的语言,他可以使用Seq来操作所有的序列,并且序列操作的指令十分的轻便。一旦熟悉,真是一门让人流连忘返的语言。这里我实践了一下序列匹配与用递归方法遍历Seq。注释写得很详细,同样直接贴代码了。

/*Seq是具体的集合类型的父类型,这些集合类型支持以确定顺序遍历其元素。
下面简单的使用一下序列的匹配
*/

val nonEmptySeq =Seq(1,2,3,4,5) //创建一个有值Seq
val emptySeq = Seq.empty[Int] //初始化一个空的seq
val nonEmptyVector = Vector(1,2,3,4,5) //创建一个有值得Vector
val emptyVector =Vector.empty[Int] //创建一个空的Vector
val nonEmpyuMap =Map("one" -> 1,"two" -> 2,"three" -> 3) //创建一个有值得map
val emptyMap =Map.empty[String,Int] //初始化一个空的map

//将这些序列合为一个大的序列,调用seqToString方法
for(seq <- Seq(
nonEmptySeq,emptySeq,nonEmptyVector,emptyVector,
nonEmpyuMap.toSeq,emptyMap.toSeq //由于map不是Seq的子类型,所以需要转换
)){
println(seqToString(seq))
}

递归的方法

//定义一个递归方法,循环匹配
def seqToString[T](seq : Seq[T]): String = seq match{
//head是seq的第一个数,tail是除了第一个之外的所有
case head +: tail =>s"$head +:"+seqToString(tail)
//为空则匹配,其实所有集合都可看做是最后粘贴一个Nil
case Nil => "Nil"
}

4.元组的匹配

说到元组,真的是个好东西,昨天在学习相关知识的时候发现,元组可以让一个方法返回两个或以上的参数。甚至是无穷无尽!这对于使用Java的我,许多原先的漫天胡猜似乎变成了可能!并且元组的使用也并不难,所以小生建议各位还是去好好的研究下元组的使用。

 //元组的匹配:通过元组的字面量,可以很容易的对元组进行匹配
val langs = Seq(
("Scala","Martin","Odersky"),
("Clojure","Rich","Hickey"),
("Lisp","John","McCarthy"))

for(tuple <- langs){
tuple match{
case ("Scala",_,_) => println("Found Scala")
case (lang,first,last) => println(s"Found other language:$lang($first,$last)")
}
}
//输出结果:
// Found Scala
// Found other language:Clojure(Rich,Hickey)
// Found other language:Lisp(John,McCarthy)

很容易,看看就懂了。

5.case中的guard语句

在匹配模式中,可以添加一些逻辑处理,另匹配更实用。

for(i <- Seq(1,2,3,4)){
i match{
case _ if i%2 == 0 =>println(s"even: $i") //这里使用了逻辑语句
case _ =>println(s"odd: $i")
}
}

6.类的匹配

前面说到的Scala的模式匹配可以对类进行匹配,甚至类中的参数。这是十分强大的!相信只要是开发过一段时间的程序员都知道。因为这样可以减少很多的判断语句,十分方便实用,接下来,就将用法贴上。

    case class Address(street: String,city:String,country: String)
case class Person(name:String,age:Int,address:Address)

val alice =Person("Alice",25,Address("1 Scala lane","Chicago","USA"))
val bob =Person("Bob",29,Address("2 Java Ave.","Miami","USA"))
val charlie =Person("Charlie",32,Address("3 Python Ct.","Boston","USA"))

for(person <- Seq(alice,bob,charlie)){
person match{
case Person("Alice",25,Address(_,"Chicago",_) )=> println("Hi Alice!")
case Person("Bob",29,Address("2 Java Ave.","Miami","USA")) =>println("Hi Bob")
case Person(name,age,_) =>
println(s"Who are you,$age year-old person name $name?")
}
}
/*结果:
Hi Alice!
Hi Bob
Who are you,32 year-old person name Charlie?
*/

Scala的模式匹配远远不止本文这些,还有诸如正则表达式,全覆盖匹配等等。这些等下篇博客再来概述。

码字不易,转发请注明出处:http://blog.csdn.net/qq_28945021/article/details/51984620