• scala模式匹配与样例类


    样本类:添加了case的类便是样本类。这种修饰符可以让Scala编译器自动为这个类添加一些语法上的便捷设定。如下:

        1.添加与类名一致的工厂方法。也就是说,可以写成Var("x")来构造Var对象。
        2.样本类参数列表中的所有参数隐式获得了val前缀,因此它被当作字段维护。

        3.编译器为这个类添加了方法toString,hashCode和equals等方法。

    模式匹配:

    match对应Java里的switch,但是写在选择器表达式之后。即: 选择器 match {备选项}。

      一个模式匹配包含了一系列备选项,每个都开始于关键字case。每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。

      match表达式通过以代码编写的先后次序尝试每个模式来完成计算。类似于UnOp("-" , UnOp("-" , e))这种形式的,是构造器模式匹配。

      match与switch的比较:匹配表达式可以被看作Java风格Switch的泛化。但有三点不同:

    1. match是Scala的表达式,始终以值作为结果;
    2. Scala的备选项表达式永远不会“掉到”下一个case;
    3. 如果没有模式匹配,MatchError异常会被抛出。这意味着必须始终确信所有的情况都考虑到了,或者至少添加一个默认情况什么都不做。如 case _ => 

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------

    代码示例:

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. /* 
    2. desc:模拟控制数学表达式的库。 
    3.       由变量、数字、一元及二元操作符组成的数学表达式。 
    4.       jb,完全照书上的来说。 
    5. */  
    6.   
    7. object simpleBegin {  
    8.     def main(args: Array[String]): Unit = {  
    9.         //--x  
    10.         println(simplifyTop(UnOp("-", UnOp("-", Var("x")))))  
    11.         //x+0  
    12.         println(simplifyTop(BinOp("+", Var("x"), Number(0))))  
    13.         //x*1  
    14.         println(simplifyTop(BinOp("*", Var("x"), Number(1))))  
    15.         //abs abs x  
    16.         println(simplifyTop(UnOp("abs", UnOp("abs", Var("x")))))  
    17.         
    18.     }  
    19.   
    20.     //层级包括一个抽象基类Expr和四个子类,每个代表一种表达式。所有的五个类都没有结构体。  
    21.     //class C 和 class C {} 一个意思。  
    22.     abstract class Expr  
    23.     case class Var(name: String) extends Expr  
    24.     case class Number(num: Double) extends Expr  
    25.     case class UnOp(operator: String, arg: Expr) extends Expr  
    26.     case class BinOp(operator: String, left: Expr, right: Expr) extends Expr  
    27.   
    28.     //“e“是什么意思????变量模式!  
    29.     //tips: case BinOp("*", e, Number(1)) => e 可以写成: case BinOp(a, e, b) => e !!!!!!!!!!!!!  
    30.     def simplifyTop(expr: Expr): Expr = expr match{  
    31.         case UnOp("-", UnOp("-", e)) => e  
    32.         case BinOp("+", e, Number(0)) => e  
    33.         case BinOp("*", e, Number(1)) => e  
    34.         //变量绑定,规则:变量 @ 模式,此时“变量”就代表了后面的“模式”:Unop("abs", _)  
    35.         case UnOp("abs", x @ UnOp("abs", _)) => x  
    36.     }     
    37.       
    38. }  

    -------------------------------------------------------------------------------------------------------------------------------------------------------------

    输出结果:

    Var(x)
    Var(x)
    Var(x)
    UnOp(abs,Var(x))

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

    模式的种类

    通配模式:case _ => 。表示默认的全匹配备选项。通配模式还可以用来忽略对象中不关心的部分。如:case BinOp(_,_,_) => XXX,则表示不关心二元操作符的元素是什么,只是检查是否为二元操作符

    常量模式 :仅匹配自身。任何字面量都可以用作常量。包括String类型。另外,任何的val或单例对象也可以被用作常量。如,单例对象Nil是只匹配空列表的模式。

    变量模式 :变量模式类似于通配符,可以匹配任何对象。不同点在于,Scala把变量绑定在匹配的对象上。之后就可以使用这个变量操作对象。如:

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. expr match{  
    2.   case 0 => "zero"  
    3.   case somethingElse => "not zero" + somethingElse  
    4. }         

     *有一个注意点:Scala使用了一个简单的文字规则来区分是一个常量还是一个变量:用小写字母开始的简单名被当作是模式变量。

    构造器模式:它的存在使得模式匹配真正变得强大。它由名称及若干括号之内的模式构成。如BinOp("+" , e , Number(0))。

    序列模式:可以像匹配样本类那样匹配List或Array这样的序列类型。同样的语法现在可以指定模式内任意数量的元素。如:

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. expr match{  
    2.    case List(0 , _ , _ ) => println("found it")  
    3.    case _ =>   
    4.  }  

    如果想匹配一个不指定长度的序列,可以指定_*作为模式的最后元素。它能匹配序列中0到任意数量的元素。

    元组模式:例子:

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. def tupleDemo(expr : Any) =   
    2.   expr match {  
    3.     case (a , b, c) => println("matched " + a + b + c)  
    4.     case _ =>   
    5.   }  

     

    类型模式:可以把它当做类型测试和类型转换的简易替代。例如:

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. def generalSize(x : Any) = x match{  
    2.   case s : String => s.length  
    3.   case m : Map[_ , _] => m.size  
    4.   case _ => 1  
    5. }  

    使用: scala> generalSize(Map(1 -> 'a' , 2 -> 'b'))

        res15 : Int = 2

    另:在Scala里类型测试和转换的代码很冗长,因为不建议这么做。

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. case BinOp("+" , x , x ) => BinOp("*" , x , Number(2))  

     

    模式守卫:模式变量仅允许在模式中出现一次。如:

      这种写法就会出错。可以改成:  case BinOp("+" , x , y ) if x == y => BinOp("*" , x , Number(2))

      模式守卫接在模式之后,开始于if。守卫可以是任意的引用模式中变量的布尔表达式。如果存在模式守卫,那么只有在守卫返回true的时候匹配才成功。

  • 相关阅读:
    vue根据不同命令打出不同环境的包
    classpath到底指的哪里
    guava的事件发布订阅功能
    枚举类型的使用
    SpringBoot自动配置的实现原理
    HttpConnection的使用
    SpringBoot下的值注入
    SpringBoot下的Job定时任务
    SpringBoot拦截器的使用
    SpringBoot+MyBatis简单数据访问应用
  • 原文地址:https://www.cnblogs.com/Evil-Rebe/p/5793422.html
Copyright © 2020-2023  润新知