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)没有定义这个数
  }
}

猜你喜欢

转载自www.cnblogs.com/SteveDZC/p/9765746.html
今日推荐