• Scala学习文档样本类与模式匹配(match,case,Option)


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

    //样本类case class
    //层级包括一个抽象基类Expr和四个子类,每个代表一种表达式
    //样本类自动添加与类名一致的工厂方法
    abstract class Expr
    case class Var(name:String) extends Expr//括号内参数不用加val,默认为加val的字段
    case class Number(num:Double) extends Expr
    case class UnOp(operator: String, arg: Expr) extends Expr
    case class BinOp(operator: String, left:Expr,right:Expr)extends Expr
      def main(args:Array[String]):Unit = {
        //1、样本类自动添加与类名一致的工厂方法,所以可以不用new就构造出相应对象
        val v = Var("x");    
        val op = BinOp("+",Number(1.0),v);
        //2、样本类参数列表中的所有参数隐式获得了val前缀,构造器中的每一个参数都成为val,除非显式生命为var(不建议)
        var s1:String = v.name 
    //3、此外将生成toString equals hashCode copy方法,除非显式定义
    //除上述外,样例类与其他类完全一样
    //============================================================//  
    //match对应于Java里的Switch //选择器 match{备选项} 取代了 switch{选择器}{备选项} //一个备选项包含了一个模式以及多个表达式,箭头符号=>隔开了模式与表达式 //本函数不对表达式进行任何的改变,只用来返回用来做匹配的表达式expr def simplifyTop(expr:Expr):Expr = expr match{ case UnOp("-",UnOp("-",e)) =>e case BinOp("+",e,Number(0))=>e case BinOp("*",e,Number(1))=>e
        case _ => expr //如果没有通配, 在匹配不到的时候抛出异常    
        }
        println(simplifyTop(BinOp("+",v,Number(0))))
        println(simplifyTop(BinOp("*",op,Number(1))))
      }

     模式匹配: 

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

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

    模式的种类

      通配模式 

        通配模式_匹配任意对象,也可以用来忽略对象中不关心的部分

      常量模式

        常量模式仅仅匹配自身。任何字面量都可以作为常量

      变量模式

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

      def pipei (x:Any) = {
        x match{
          case 0 => "zero"  //常量模式
          case somethingElse => "not zero" + somethingElse  //变量模式
        }
      }

      构造器模式

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

      序列模式

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

        val myList = List(1,1,2,3)
        def findL(l1:List[Int]):Unit={
            l1 match{
              case List(0,1,_,_) =>println("找到了!");
              case _ =>println("没找到!");
            }
        }
        findL(myList)

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

      元组模式

     def tupleDemo(expr : Any) = 
    expr match {
    case (a , b, c) => println("matched " + a + b + c)
    case _ =>
    }

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

     def generalSize(x : Any) = x match{
    case s : String => s.length
    case m : Map[_ , _] => m.size
    case _ => 1
    }

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

          res15 : Int = 2

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

      模式守卫

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

    case BinOp("+" , x , x ) => BinOp("*" , x , Number(2))

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

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

      类型擦除:

    def isIntMap(x:Any)={
          x match{
            case m: Map[Int,Int]=>true
            case _ =>false
          }
        }
        val m1 =Map(1->11,2->22)
        val m2 = Map("s1"->"sss111")
        println(isIntMap(m1))
        println(isIntMap(m2))
    打印出  true
         true

    第一个true看起来正确,第二个true看起来不合理,因为只能判断出是某种参数类型的Map,而不能判断出参数类型

    擦除规则的唯一例外就是数组。

    //数组的类型,不擦除    
        def isStringArray(x:Any)={
          x match{
            case s:Array[String]=>true
            case _=> false
          }
        }
        val a1 = Array("aa","bb")
        val a2 = Array[Int](1,2)
        println(isStringArray(a1))
        println(isStringArray(a2))

    打印出   true

        false

      变量绑定

    如果匹配成功,把变量设置成匹配的对象

        //变量绑定
        def doubleABS(expr:Expr)={
          expr match{
            case UnOp("abs",e @ UnOp("abs",_))=>e    //相当于把UnOp("abs",_)绑定到e,以便后面使用
            case _ =>
          }
        }
        val e1 = UnOp("abs",UnOp("abs",v))
        println(doubleABS(e1))

    输出:UnOp(abs,Var(x)) 

    模式守卫

    模式守卫开始于if 只有在守卫返回true时匹配才成功。

    //模式守卫
        def simplifyAdd(expr:Expr)={
          expr match{
            //case BinOp("+",x,x)=>BinOp("*",x,Number(2))错误,不能有两个x,模式变量仅允许在模式中出现一次
            case BinOp("+",x,y) if(x==y )=>BinOp("*",x,Number(2))
            case _=>expr
          }
        }

    封闭类

    sealed abstract class Expr //加上sealed 代表封闭类
    case class Var(name:String) extends Expr//括号内参数不用加val,默认为加val的字段
    case class Number(num:Double) extends Expr
    case class UnOp(operator: String, arg: Expr) extends Expr
    case class BinOp(operator: String, left:Expr,right:Expr)extends Expr
    //封闭类除了类定义所在的文件之外,不能再添加任何新的子类。
    //如果使用继承自封闭类的样本类做匹配,若缺失了某种模式组合,编译器将警告
    //封闭类的使用
        def fengbi(expr:Expr)={
          expr match{    //有警告标志,因为丢失了可能样本的模式匹配
            case BinOp("+",e,y)=>e;
          }
        }

    编译后的警告

    Description Resource Path Location Type
    match may not be exhaustive.

    It would fail on the following inputs:

    BinOp((x: String forSome x not in "+"), _, _), Expr(), Number(_), UnOp(_, _), Var(_)

    Test1.scala /test14/src/com/evor/test14 line 93 Scala Problem

    Option类型

    def main(args:Array[String]):Unit = {
        val captials = Map("China"->"Beijing","France"->"Paris")
        val c = captials.get("China")    //get方法返回可选值,Map的get方法在找到指定键时返回Some(value),否则返回None
        val a = captials.get("Americas")
        println(c)
        println(a)
        
        def show(x:Option[String])={ //通过模式匹配,分离可选值
          x match{
              case Some(s)=>s
              case None=> "Don't know." //如果可选类型为None 返回don't know
          }
        }
        println(show(c))
        println(show(a))
      }

    运行结果:

    Some(Beijing)
    None
    Beijing
    Don't know.

  • 相关阅读:
    Educational Codeforces Round 86 (Rated for Div. 2)
    第十六届东南大学大学生程序设计竞赛(春、夏季)
    Codeforces Round #643 (Div. 2)
    [P3384] 【模板】轻重链剖分
    [BJOI2012] 连连看
    [CF1349C] Orac and Game of Life
    Codeforces Round #641 (Div. 2)
    [TJOI2018] 数学计算
    [CF1157D] N Problems During K Days
    [CF1163C1] Power Transmission (Easy Edition)
  • 原文地址:https://www.cnblogs.com/gnivor/p/4079132.html
Copyright © 2020-2023  润新知