• 二. 模式匹配


    一. 更好的switch:match

    1. match匹配任何类型
      scala> var ch = '*'
      ch: Char = *
      
      scala> var sign=""
      sign: String = ""
      
      scala> ch match{  // match表达式         
           |     case '+' => sign="1"
           |     case '-' => sign="-1"
           |     case _ => sign="not in +/-"
           | }
      
      scala> print(sign)
      not in +/-
      

    【注】:
    (1)与java不同,match中的每个case语句,不需要显示的声明break,不用担心“跳入下一个分支”
    (2)如果未声明case _ 来匹配任一选项,则会抛出MatchError异常
    (3) 与if类似,match是表达式,而非语句

    1. 带守卫的match
      守卫是一个boolean类型的条件,用来给case _加限定条件

      scala> ch match {
           |     case '+' => sign="0"
           |     case _ if Character.isDigit(ch) => sign="is digit"  // 守卫
           |     case _ => sign="orthers"
           | }
      
      scala> print(sign)
      is digit
      
    2. case的常量匹配
      case可用常量匹配,scala识别常量的方法是:以大写字母开头的名字认为是常量。所以,如果匹配小写字母开头的常量,需要将常量用反引号扩起来

      scala> val ADD = "+"
      ADD: String = +
      
      scala> var ch = "+"
      ch: String = +
      
      scala> ch match {
           |     case ADD => print("111")    // 大写开头的ADD,scala自动识别为常量匹配
           |     case "-" => print("222")
           | }
      111
      
      scala> val add="+"
      scala> ch match {
           |     case `add` => print("111")   // 小写字母开头的常量反引号引起来:`add`
           |     case "-" => print("222")
           | }
      111
      
      
    3. 变量数值类型的匹配
      (1)scala用match匹配变量的参数类型,而不去时用isInstanceOf操作符
      (2)如果match返回的结果依赖于需要匹配的变量值,则case语句后面加上别名
      (3)类型匹配不能去匹配集合泛型,因为泛型是编译时期约束,而match是运行时代码

      var obj:Any = "11"    
      val result = obj match{
          case x: Int => 2 * x
          case s: String => Integer.parseInt(s)+"aaa"
          case _ => 0
      }
      println(obj)    //11
      println(result) //11aaa
      
      
      var obj2:Any="11"
      val result2 = obj2 match {
        case _ : Int => 111       // result2的表达式用不上obj2,不用起别名
        case _ => 0
      }
      println(result2)
      
    4. 数组,List, 元组的模式匹配
      (1)数组:数组的匹配项可以匹配任意长度的Array
      (2)List:list时固定长度的列表,list分为head和tail2部门,head时list的第一个元素,tail是list中除了head外的其余元素组成的list。用::连接list时,尾节点要声明成Nil
      (3)元组:元组的匹配项,要与原元组用相同的元素个数,元素类型

      //1. Array匹配
      var arr = Array(1,2,3)
      val s: String = arr match {
        case Array(0) => "0"
        case Array(x,y) => "2 param array"
        case Array(1, _*) => "1 ..."
        case _ => "anything else"
      }
      print(s)
      
      //2. List匹配
      var digitList = List(1,2,4)
      var list2 = 9 :: List(4,2) :: 2 :: Nil  //list
      
      val value: Any = list2 match {
        case 9 :: Nil => 9
        case x :: y :: Nil => x + "" + y
        case _ => "something else"
      }
      print(value)   //something else
      
      //3. 元组匹配
      var tuple1 = (1,"abc",'d')
      tuple1 match {
        case (0,"asd", _) => "haha"
        case (x,y,'d') => "d"
        case _ => "anything"
      }
      

    三. 其他模式

    1. 集合声明中的模式
      (1)元组声明中的变量匹配

      val (x,y) = (1,2)
      print(x)   //1
      

    (2)数组声明中的变量匹配
    scala val arr = Array(1,2,3) var Array(first,scend,3) = arr print(first) //1

    1. for推导式的模式匹配
      import scala.collection.JavaConversions.propertiesAsScalaMap     //将java的properties转换成scala的映射
      
      for((k,v) <- System.getProperties){
        print(k+"==>"+v)
      }
      
      for((k,"") <- System.getProperties){
        println(k)
      }
      // 带守卫的for
      for((k,v) <- System.getProperties if v==""){
        println(k)
      }
      

    四. 样例类

    1. case类与普通类的区别
      (1)构造器的每一个参数都默认为val的,除非它被显式地声明成var
      (2)case类的伴生对象自动加上apply方法,使得不用new关键字就能构造处对象
      (3)自动生成unapply()方法供提取器模式匹配
      (4)自动产生toString,equals,hashCode,copy方法。其他特性和普通类相同,如继承等

      abstract class Amount
      
      case class Dollar(value:Double) extends Amount                   //样例类
      case class Currency(value:Double,unit:String) extends Amount
      case object Nothing extends Amount                               //样例对象
      
      //样例类模式匹配
      val amt:Any = Currency(11.2,"asd")
      val s: String = amt match {
        case Dollar(v) => "$" + v
        case Currency(_, v) => "i got " + v
        case Nothing => ""
      }
      s //i got asd
      
      class A(value:String){}
      var aa = new A("111")  //普通类不会自动加上apply()
      
    2. copy方法和带名参数
      copy()方法创建了一个与对象值相同的新对象,可以制定参数值类构建新对象

      val amt2 = Currency(29.95,"EUR")
      val price = amt2.copy()              //price: Currency = Currency(29.95,EUR)
      val price2 = amt2.copy(value=11.2)   //price2: Currency = Currency(11.2,EUR)
      val price3 = amt2.copy(unit="CHF")   //price3: Currency = Currency(29.95,CHF)
      

    五. Option类型

    1. Option类是一个样例类,常用于表示函数的返回值类型:Option[T]。表示那种可能存在,也可能不存在的值。
    2. 存在的值用子类Some包装。eg:Some("Fred"),表示返回fred字符串
    3. 不存在的值用None表示
      object Test extends App{
      
        private val map: Map[String, Int] = Map(("fred",1),("lucy",2))
        map.get("fred") match { // map的get方法返回Option类型,模式匹配用Some或none匹配
          case Some(1) => println(1)
          case None => println("no value")
        }
        
        //getOrElse方法利用上面的模式匹配
        map.getOrElse("zhangsan",{println("no value")})     //no value
      }
      
      

    六. 偏函数

    1. 偏函数:没有定义所有情况的case语句块
    2. 偏函数常用于参数传入
      object TestLazyView extends App{
        val res = "-3+4".collect({case '-' => 1;case '+' => -1})   //Vector(1, -1)
        println(res)
      }
      
      
  • 相关阅读:
    alpha冲刺3
    alpha冲刺2
    alpha冲刺1
    软工第七次作业
    软工第八次作业
    软工第六次作业
    软工第五次作业
    软工第四次作业
    Alpha冲刺一 (2/10)
    Alpha冲刺一(1/10)
  • 原文地址:https://www.cnblogs.com/72808ljup/p/5409033.html
Copyright © 2020-2023  润新知