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

码字不易,转发请注明出处: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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值