zoukankan      html  css  js  c++  java
  • Scala模式匹配--样例类--密封样例类--偏函数

    Scala模式匹配--样例类--密封样例类--偏函数

    模式匹配

    等价于java的switch case
    		val c = '+'
    		c match{
    			case '+' => println(111)
    			case '-' => println(222)
    			case _ => println(0)
    		}
    

    匹配常量

    //匹配值,没有break
    val x :Char= '+'
    //万一xx存在这种可能case '-'=>"100" case _=>0.0F
    //val xx :Int=x match{
    val xx :Any=x match{ //Any所有类的超类
      case '+'=>100
      case '-'=>"100"
      case _=>0.0F
    }
    

    守卫条件

    val x = c match{
    		  case '+' => 1
    		  case '-' => -1
    		  case _ if Character.isDigit(c) => 'N'
       //case _if x.isDigit=>0.0F 它如果是数字
    		  case _ => 'X'
    		}
    val x :Char='9'
    val xx:Any=x match{
      case '+'=>100
      case '-'=>"100"
      case _if x.isDigit=>println("is number")  //if x.isDigit这里就是守卫条件
      case _=>println(x)
    }
    //守卫可以是任何Boolean条件。
    注意模式总是从上往下进行匹配。如果带守卫的这个模式不能匹配,则捕获所有的模式(case_)会被用来尝试进行匹配。
    

    使用变量:如果case关键字后面跟着一个变量名,那么匹配的表达是会被赋值给那个变量。

    val str = "hello"
    		str(0) match{
    		  case '+' => println(1)
    		  case '-' => println(2)
    		  case ch => println(ch)
    		}
    

    常量问题,大写会识别成常量,小写是变量,如果让小写也是常量,使用``标出

    val str = "hello"
    		val ch = 'h'
    		str(0) match{
    		  case '+' => println(1)
    		  case '-' => println(2)
    		  case `ch` => println(`ch`)
    		}
    
    

    类型匹配

    val x:Any = "abc"
    		x match{
    		  case a:Int => println(1)
    		  case a:String => println(2)
    		  case a:Float => println(3)
    		  case _ => println(0)
    		}
    
    

    匹配数组

    val arr=Array(0)        //  100 is Int
    val arr=Array(0,1)      //2=>x:0
    val arr=Array(0,1,2,3) //default
    arr match{
        //精确匹配
        case Array(0)=>println(1)  
        //匹配两个元素
        case Array(x,y)=>println(2+"=>x: "+x)
        //匹配0为首个元素
        case Array(0,_*)=>println(3)
        case _=>println("default")
    }
    
    val arr = Array[Int](1,2,3)
    		arr match{
    		  //case Array(0) => println(1)			//精确匹配(0)
    		  case Array(x,y) => println(2)			//匹配2个元素
    		  case Array(0,_*) => println(3)		//匹配0开始
    		  case _ => println(4)					//
    		}
    总结:第一个模式匹配包含0的数组。第二个模式匹配任何带有两个元素的数组,并且将这两个元素分别绑定到变量x和y中。第三个表达式匹配任何以零开始的数组。
    

    匹配集合(List)

    val list = 0::1::2::Nil
    		list match{
    		  case 0::Nil => println(1)				//0
    		  case x::y::Nil => println(2)			//x,y
    		  case 0::tail => println(3)			       //0,...
    		  case _ => println(4)
    		}
    
    val list=1::2::Nil      //2 =>x: 1
    val list=0::1::2::Nil   //List(1,2)
    list match{
        //精确匹配
        case 0::Nil=>println(1)
        //匹配两个元素
        case x::y::Nil=>println(2+"=>x: "+x)
        //匹配0为首个元素
        case 0::tail=>println(tail)
        case _=>println("default")
    }
    

    匹配元组

    val t = (1,2)
    		t match{
    		  case (0,_) => println(1)
    		  case (y,0) => println(2)
    		  case _ => println(3)
    		}
    val t=(0,1) //100
    val t=(1,0) //200  必须符合case里面的条件才行
    t match{
       case(0,_)=>println("100")
       case(x,0)=>println("200")
       case _ =>println("default")
    }
    
    val(x,y)=(1,2)
    同时把x定义为1,把y定义为2.这对于使用那些返回对偶的函数而言很有用
    val (q,r)=BigInt(10)/%3
    /%方法返回包含商和余数的对偶,而这两个值分别被变量q和r捕获到。
    

    提取器unapply / unapplySeq

    val arr = Array(1,2,3)
    		arr match{
    		  case Array(x,y,z)=> printf("x=%d,y=%d,z=%d" , x , y  ,z)
    		  case _ => println("0")
    		}
    scala> val t=<1,2>
    t:<Int,Int>=<1,2>
    scala> val<x,y>=t  //可以同时把t给抽出来
    x:Int=1
    y:Int=2
    scala> val<x,y>=t
    
    //反向抽取
    //如果元素很多,可以用t给抽出来
    scala>val t=<1,"tom",12,"henan">
    t:<Int,String,Int,String>=<1,tom,12,henan>
    scala>val<id,name,age,addr>=t
    id:Int=1
    name:String=tom
    age:Int=12
    addr:String=henan
    

    多个变量声明模式

    val (x,y,z) = (1,2,3)
    		x = 1
    		y = 2
    		z = 3
    //模式匹配的变量声明模式
    val t=(1,"tom",12,"henan")  //这个就是元组
    val (id,name,age,addr)=t
    println(id)
    [源码解析]
    Tuple4  extends(继承)Product4
    object Product4{
      def unapply[T1,T2,T3,T4]  (x:Product4[T1,T2,T3,T4]):Option[Product4[T1,T2,T3,T4]]=Some(x)
      option类型(Some(类) , None(单例对象))
    }
    ------------------
    //同时提取商和余数
    val (a,b)=BigInt(5) /% 3
    val arr=Array(1,2,3,4)
    val Array(x,y,_*)=arr  //for循环的map迭代
    println(x+","+y)//1,2
    val map=Map(1->"tom1",2->"tom2")
    //相当于反向抽取(常见的形式)
    for((k,y)<-map ){
      println(k+"="+v)
    }
    
    

    抽取前两个元素依次赋值

    val Array(x,y,_*) = Array(1,2,3,4,5)
    
    		val map = Map(1->"tom1" , 2->"tom2",3->"tom3")
    		for((k,_) <- map) println(k)
    		for(t <- map) println(t._1)
    //模式匹配的变量声明模式
    

    样例类

    .样例类是一种特殊的类,它们经过优化以被用于模式匹配。内置实现了很多便捷的方法,比如apply/unapply/serilizable/compare/toString

    abstact classAmount  //一个抽象类
    //定义了两个样例类
    case class Dollar(value:Double)extends Amount
    case class Currency(value: Double,unit: String)extends Amount  //样例类必须要有属性
    //通过普通类定义一个子类,它和样例类有啥区别
    object CaseClassDemo{
      def main(args:Array[String]):Unit={
        abstract class Amount
        //定义样例类  
        //sealed(密封),样例子类和样例父类如果不加sealed是可以定义在不同的scala文件里的 如果加了sealed就必须跟它的父类定义在同一个Scala文件中
        //case class Dollar(cnt:Int)extends Amount样例子类,sealed的优点是:在一个scala文件中可以找到它所有的sealed子类,就不会存在在其它的包里面或文件夹里面。
        sealed case class Dollar(cnt:Int)extends Amount
        case class RenmiYuan(cnt:Int)extends Amount
        //定义一个样例对象
        case object NoMoney extends Amount
        //可以实例化对象(快速构建对象)
        //apply
        val d1=Dollar(10)
        //apply
        val r1=RenmiYuan(100)
        //打印      --因为里面已经重新了toString方法
        println(d1)  //Dollar(10)
        println(r1)  //RenmiYuan(100)
        //快速抽出里面的属性
        //unapply
        val Dollar(x)=d1  //10
         //unapply
        val RenmiYuan(y)=r1 //100
        println(x)
        //Serializable(scala)继承java里面的,就是java里面的串行化接口实现
        package scala
        trait Serializable extends Any with java.io.Serializable
     -------------样例对象模式匹配----------------- 
        //给样例对象变量,是否可以模式匹配,这里用到的都是unapply反解析
        val m=Dollar(300)    //300美元 
        val m:Amount=RenmiYuan(300)//300人民币
        val m:Amount=NoMoney  //NoMoney本来就是样例对象
        //模式匹配,判断它是美元还是人民币
        //对样例实例进行模式匹配
        m match{
          case Dollar(x)=>println(x+"美元")
          case RenmiYuan(y)=>println(y+"人民币")
          case NoMoney=>println("没钱")
        }
      }
    }
    

    密封样例类

    必须将样例子类和父类定义在一个scala文件中。
    方便在一个scala文件中找到所有的子类。不允许在其他地方定义
    子类。和匹配模式配合使用,非常方便。
    //sealed 密封
    sealed abstract class Dog
    case class Jing8(var name:String) extends Dog
    case class Shapi(var name:String) extends Dog
    [典型的密封样例类源码]
    //Option密封抽象类
    sealed abstract class Option[+A]extends Product with Serializable
    它的两个子类 None  Some
    //None子对象(样例对象)
    case object None extends Option[Nothing]{
      def isEmpty=true
      def get=throw new NoSuchElementException("None.get")
    }
    //Some(样例类)
    final case class Some[+A](x: A)extends Option[A]{
      def isEmpty=false
      def get=x
    }
    

    偏函数(PartialFunction)

    被包在花括号内的一组case语句是一个偏函数---一个并非对所有输入值都有定义的函数。它是PartialFunction[A,B]类的一个实例。(A是参数类型,B是返回类型。)该类有两个方法:apply方法从匹配到模式技术函数值,而isDefinedAt方法在输入至少匹配其中一个模式时返回true.

    模式匹配有一个缺点就是代码需要重用,假如很多地方需要用到模式匹配。就需要反复的写这些东西,完全可以{}包起来的一组case给它封装成一个对象,这个对象就叫做偏函数。偏函数还有一种情况就是,它没有完全把所有的情况罗列完整。它只是一部分,或者是若干情况。
    偏函数的作用:偏函数就是对模式匹配代码进行重用,以备于在其它的地方还可以利用这段代码执行模式匹配的动作。
    //偏函数,对模式匹配的封装,重用模式匹配的代码
    object PartialFunctionDemo{
      def main(args:Array[String]):Unit={
        val ch:Char='+'
        val r=ch match{
          case '+'=>1
          case '-'=>-1
          case _=>0
        }
        println(r) //1
        //定义一个偏函数对象(类),代码就是把case放进去
        val f:PartialFunction[Char,Int]={
          case '+'=>1
          case '-'=>-1
          case _=>0
        }
        //isDefinedAt是否定义了这种情况,它是判断是否有没有定义这种情况的处理
        println(f.isDefinedAt('+')) //1
        println(f.isDefinedAt('9')) //true  如果把//case _=>0注释点就 false
        //调用这个
        println(f.apply('+')) //1
        //可以简写
        println(f('-'))   //-1
        println(f('9'))//注释掉 case _=>0,则抛异常(MatchError)没有定义这个数
      }
    }
    
  • 相关阅读:
    Python NLPIR(中科院汉语分词系统)的使用 十五分钟快速入门与完全掌握
    Python NLPIR(中科院汉语分词系统)的使用 十五分钟快速入门与完全掌握
    源码:我的关于NLP的博客(持续更新中...)
    源码:我的关于NLP的博客(持续更新中...)
    orm功能封装
    元类
    事件,存储
    索引
    mysql课外积累
    day35作业
  • 原文地址:https://www.cnblogs.com/SteveDZC/p/9765746.html
Copyright © 2011-2022 走看看