Scala_模式匹配_2_对象_样例类_sales测试

对象匹配
case中对象的unapply方法(对象提取器) 返回Some集合则为匹配成功 ;返回none集合则为匹配失败

1 构建对象时apply会被调用 ,比如 val n1 = Square(5)
2 当将 Square(n) 写在 case 后时[case Square(n) => xxx],会默认调用unapply 方法(对象提取器) 
3 number 会被 传递给def unapply(z: Double) 的 z 形参
4 如果返回的是Some集合,则unapply提取器返回的结果会返回给 n 这个形参
5 case中对象的unapply方法(提取器)返回some集合则为匹配成功
6 返回none集合则为匹配失败

7  当case 后面的对象提取器方法的参数为多个,则会默认调用def unapplySeq() 方法
8  如果unapplySeq返回是Some,获取其中的值,判断得到的sequence中的元素的个数,如果是三个,则把三个元素分别取出,赋值给f1 f2 和f3

object MatchObjectTest {
  def main(args: Array[String]): Unit = {
    var num: Double = Square(5)
    val namesString = "Alex:Bob:Sumi" //字符串
    val name2 = namesString.split(":")
//    println( name2.getClass + " : " + name2.mkString ) //[Ljava.lang.String
//    for (i <- name2){println(i )}
    //  执行 num match { case  Square(a)}
    // 1 调用 unapply(arg: Double) 将 num传入,返回Some(math.sqrt(arg)) 例 Some(6)
    // 2 将返回值 6 给 a
    // 3 如果没有匹配到 返回None
    num match {
      case Square(a) => println(a)
      case _ => println("啥也不是 完蛋")
    }
    //  当执行  case Names(n1, n2, n3)
    //  1. 会调用 unapplySeq(str),把 "Alex:Bob:Sumi"传入给 str
    //  2. 如果 返回的是 Some("Alex:Bob:Sumi"),分别给 (n1, n2, n3)
    //   注意,这里的返回的值的个数需要和(n1, n2, n3)要一样
    //  3. 如果返回的None ,表示匹配失败
    namesString match {
      case Names(n1, n2, n3) => println(s"$n1 $n2 $n3")
      case _ => println("啥也不是 完蛋")
    }
  }
}

object Square {
  def unapply(arg: Double): Option[Double] = { //拆解对象,对象提前器
    println("this is " + arg)
    //1. unapply方法是对象提取器 ; 接收arg:Double 类型 返回类型是Option[Double]
    //2. 返回的值是 Some(math.sqrt(arg)) 返回arg的开平方的值,并放入到Some(x)
    Some(math.sqrt(arg))
  }

  def apply(arg: Double): Double =  arg * arg  //构造对象
}

object Names {
  //当构造器是多个参数时,就会触发这个对象提取器
  def unapplySeq(str: String): Option[Seq[String]] = {
    if (str.contains(":")) Some(str.split(":"))
    else None
  }
}

样例类( 模板类 )

1 样例类仍然是类, 用case关键字进行声明, 为模式匹配而优化的类
2 构造器中的参数都成为val ——除非它被显式地声明为var(不建议)  //底层对应private final double value;

3 在样例类对应的伴生对象中提供apply方法让 ,不用new关键字 就能构造出相应的对象 ,提供unapply方法让模式匹配可以工作
4 将自动生成toString、equals、hashCode和copy方法(有点类似模板类,直接给生成,供程序员使用)
5 可以添加方法和字段,扩展它们
5 样例类的copy方法和带名参数 (copy创建一个与现有对象值相同的新对象 并可以通过带名参数来修改某些属性)

 中置表达式  1 + 2 操作符是以中缀形式处于操作数的中间(例:3 + 4)
 如果unapply方法产出一个元组,可以在case语句中使用中置表示法 (匹配List 序列)

object Casedemo1 {
  def main(args: Array[String]): Unit = {

    // 样例类( 模板类 )
    for (item <- Array(Dollar(999.0), Currency(888.0, "RMB"), NoAmount)){
      val result = item match {
        // case Dollar(a) 1 调用Dollar 底层 unapply(999.0) 2 返回some(999.0) 3 a = 999.0 ; 4("usd" ,999)
        case Dollar(a) => ("usd", a )
        case Currency(a, b) =>  (b, a)  //unapply(888.0, "RMB") => some(888.0, "RMB") => (a,b) =>(b,a)
        case NoAmount => "啥也不是 完蛋"
      }
      //Dollar(999.0)-> (usd,999.0) //Currency(888.0,RMB)-> (RMB,888.0) NoAmount-> 啥也不是 完蛋
//      println(item + "-> " + result )
    }

    //克隆 样例类的copy方法和带名参数
    val d1 = Dollar(20.0)
    val d2_clone = d1.copy() // 克隆,创建的对象和d1的属性一样
    val d3_clone = d1.copy(200)  // 可以通过 参数来修改某些属性值
    println(d2_clone + "->"+ d2_clone.value)   //能直接打印d2_clone because 重写了toString
    println(d3_clone + "->"+ d3_clone.value)
    // 中置表达式  1 + 2 操作符是以中缀形式处于操作数的中间(例:3 + 4)
    // 如果unapply方法产出一个元组,可以在case语句中使用中置表示法

    List(1, 3, 5, 9) match {
      //1.两个元素间::叫中置表达式,至少first,second两个匹配才行.
      //2.first 匹配第一个 second 匹配第二个, rest 匹配剩余部分(5,9)

      // 1 3 2 List(5,9)
      case first :: second :: rest => println(first + " " + second  + " "+ rest.length + " " + rest)
      case _ => println("匹配不到...")
    }
  }
}

匹配嵌套结构操作原理类似于正则表达式

如果一个类 仅仅想在当前文件用,就使用sealed 类 

object SalesTest {
  def main(args: Array[String]): Unit = {
    //, Book("天龙八部", 100)
    var sales1  = Bundle("书籍", 10 ,Book("漫画", 40) , Bundle("文学作品", 20, Book("《阳关》", 80), Book("《围城》", 30)))
    val result = sales1 match {
//      case Bundle(_, _, Book(name, _), _*) => name
      case Bundle(_,_, b1 @ Book(_,_), b2 @ _) => (b1,b2)  //ArraySeq
      case _ => "啥也不是"
    }
//    println(result)
    val result_1 = count_price(sales1)
    println(result_1)

  }
  def count_price (b: Items): Int={
    b match {
      case Book(_, price1) => price1
      case Bundle(_, discount_price, others @ _*) => others.map(count_price).sum - discount_price
    }
  }

}
abstract sealed class Items

case class Book(information: String, price : Int ) extends Items
case class Bundle(information: String ,discount: Int, item: Items*) extends Items
posted @ 2021-05-04 14:41  hzcya911  阅读(2)  评论(0)    收藏  举报