zoukankan      html  css  js  c++  java
  • Scala模式匹配

    [toc]

    ## Scala模式匹配

    > Scala中的模式匹配`类似于Java中的switch语法`,但是更加强大。
    >
    > 模式匹配语法中,采用==match关键字声明==,每个分支==采用case关键字==进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有case都不匹配,那么会执行`case _ 分支`,类似于Java中default语句。

    ### 1. Scala模式匹配快速入门

    ~~~~scala
    /**
    * @Date 2021/4/3 14:55
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchDemo01 {
    def main(args: Array[String]): Unit = {
    val oper = '+'
    val n1 = 20
    val n2 = 10
    var res = 0

    /**
    * 说明
    * 1. match (类似java switch) 和 case 是关键字
    * 2. 如果匹配成功, 则执行 => 后面的代码块.
    * 3. 匹配的顺序是从上到下,匹配到一个就执行对应的 代码
    * 4. => 后面的代码块 不要写 break,会自动的退出match
    * 5. 如果一个都没有匹配到,则执行 case _ 后面的代码块
    */
    oper match {
    case '+' => res = n1 + n2
    case '-' => res = n1 - n2
    case '*' => res = n1 * n2
    case '/' => res = n1 / n2
    case '%' => res = n1 % n2
    case _ => println("oper error")
    }

    println("res = " + res)
    }
    }
    ~~~~

    > match的细节和注意事项:
    >
    > 1. 如果所有case都不匹配,那么会执行case _ 分支,类似于Java中default语句
    > 2. 如果所有case都不匹配,又没有写case _ 分支,那么会抛出MatchError
    > 3. 每个case中,不用break语句,自动中断case
    > 4. 可以在match中使用其它类型,而不 仅仅是字符
    > 5. `=>` 等价于 java swtich 的 `:`
    > 6. `=>` 后面的代码块到下一个 case, 是作为一个整体执行,可以使用{} 扩起来,也可以不扩。

    #### 条件守卫

    如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫。

    ```scala
    /**
    * @Date 2021/4/3 15:21
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchIfDemo01 {
    def main(args: Array[String]): Unit = {
    /**
    * 是对"+-3!" 遍历
    */
    for (ch <- "+-3!") {

    var sign = 0
    var digit = 0
    // 模式匹配
    ch match {
    case '+' => sign = 1
    case '-' => sign = -1

    /**
    * 如果 case 后有 条件守卫即if ,那么这时的 _ 不是表示默认匹配
    * 表示忽略传入的 ch
    */
    case _ if ch.toString.equals("3") => digit = 3
    case _ if (ch > 1110 || ch < 120) => println("ch > 10")
    case _ => sign = 2
    }

    /**
    * 分析
    * + 1 0
    * - -1 0
    * 3 0 3
    * ! 2 0
    * ch + "" + sign + " " + digit
    */
    println(s"\nch = $ch \nsign = $sign \ndigit = $digit")
    }
    }
    }
    ```

    #### 课堂练习

    > 练习一:

    ~~~~scala
    /**
    * @Date 2021/4/3 15:40
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchExercise01 {
    def main(args: Array[String]): Unit = {

    for (ch <- "+-3!") {

    var sign = 0
    var digit = 0

    ch match {
    case '+' => sign = 1
    case '-' => sign = -1
    // 可以有多个 默认匹配,但是后面的默认匹配无效,编译器没有报错
    case _ => digit = 3
    case _ => sign = 2
    }

    /**
    * + 1 0
    * - -1 0
    * 3 0 3
    * ! 0 3
    */
    println(s"\nch = $ch \nsign = $sign \ndigit = $digit")
    }
    }
    }
    ~~~~

    > 练习二:

    ~~~~scala
    /**
    * @Date 2021/4/3 16:00
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchExercise02 {
    def main(args: Array[String]): Unit = {
    for (ch <- "+-3!") {

    var sign = 0
    var digit = 0

    ch match {
    case _ if ch > 10000 => digit = 3
    case '+' => sign = 1
    case '-' => sign = -1
    // 说明..
    case _ => println("没有任何匹配~~~")
    }

    /**
    * 结果分析
    * + 1 0
    * - -1 0
    * 没有任何匹配~~~ 3 0 0
    * 没有任何匹配~~~ ! 0 0
    */
    println(s"\nch = $ch \nsign = $sign \ndigit = $digit")
    }
    }
    }
    ~~~~

    #### 模式中的变量

    > 如果在case关键字后跟变量名,那么match前表达式的值会赋给那个变量

    ~~~~scala
    /**
    * @Date 2021/4/3 16:05
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchVarDemo01 {
    def main(args: Array[String]): Unit = {
    val ch = 'U'
    // 模式匹配
    ch match {
    case '+' => println("ok~")
    // 下面 case mychar 含义是 mychar = ch
    case mychar => println("ok~" + mychar)
    case _ => println("ok~~")
    }

    val ch1 = '+'
    /**
    * match是一个表达式,因此可以有返回值
    * 返回值就是匹配到的代码块的最后一句话的值
    */
    val res = ch1 match {
    case '+' => ch1 + " hello "
    // 下面 case mychar 含义是 mychar = ch
    case _ => println("ok~~")
    }

    println("res = " + res)
    }
    }
    ~~~~

    > 变量声明中的模式:match中每一个case都可以单独提取出来,意思是一样的。

    ~~~~scala
    /**
    * @Date 2021/4/3 16:52
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchVarDemo02 {
    def main(args: Array[String]): Unit = {
    val (x, y, z) = (1, 2, "Hello")

    /**
    * x = 1
    * y = 2
    * z = Hello
    */
    println(s"x = $x\ny = $y\nz = $z\n")
    /**
    * i = BigInt(10)/3
    * j = BigInt(10)%3
    */
    val (i, j) = BigInt(10) /% 3

    /**
    * i = 3
    * j = 1
    */
    println(s"i = $i\nj = $j")
    val arr = Array(1, 3, 5, 7, 9)
    // 提出 arr 的前两个元素
    val Array(first, second, _*) = arr

    /**
    * first = 1
    * second = 3
    */
    println(s"first = $first \nsecond = $second")
    }
    }
    ~~~~

    #### For表达式中的模式

    for表达式中的模式

    ~~~~scala

    /**
    * @Date 2021/4/3 17:18
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchForDemo01 {
    def main(args: Array[String]): Unit = {

    val map = Map("A" -> 1, "B" -> 0, "C" -> 3)

    // 出来三个key-value ("A"->1), ("B"->0), ("C"->3)
    for ((k, v) <- map) {
    println(k + " -> " + v)
    }

    /**
    * 说明 : 只遍历出 value = 0 的key-value ,其它的过滤掉
    */
    println("--------------(k, 0) <- map-------------------")
    for ((k, 0) <- map) {
    println(k + " --> " + 0)
    }

    /**
    * 说明:这个就是上面代码的另外写法,只是下面的用法灵活和强大
    */
    println("--------------(k, v) <- map if v == 0-------------------")
    for ((k, v) <- map if v >= 1) {
    println(k + " ---> " + v)
    }
    }
    }
    ~~~~

    ### 2. Scala模式匹配详解

    #### 类型匹配

    > 可以匹配对象的任意类型,这样做避免了使用isInstanceOf和asInstanceOf方法

    ~~~~scala
    /**
    * @Date 2021/4/3 16:09
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchTypeDemo01 {
    def main(args: Array[String]): Unit = {
    val a = 8
    // 说明 obj 实例的类型 根据 a 的值来返回
    val obj = if (a == 1) 1
    else if (a == 2) "2"
    else if (a == 3) BigInt(3)
    else if (a == 4) Map("aa" -> 1)
    else if (a == 5) Map(1 -> "aa")
    else if (a == 6) Array(1, 2, 3)
    else if (a == 7) Array("aa", 1)
    else if (a == 8) Array("aa")

    /**
    * 根据 obj的类型来匹配
    */
    val result = obj match {
    case a: Int => a
    case b: Map[String, Int] => "对象是一个字符串-数字的Map集合"
    case c: Map[Int, String] => "对象是一个数字-字符串的Map集合"
    case d: Array[String] => d //"对象是一个字符串数组"
    case e: Array[Int] => "对象是一个数字数组"
    case f: BigInt => Int.MaxValue
    case y: Float => println("xx")
    case _ => "啥也不是"
    }

    println(result)
    }
    }
    ~~~~

    > 类型匹配注意事项:
    >
    > 1. Map[String, Int] 和Map[Int, String]是两种不同的类型,其它类推。
    >
    > 2. 在进行类型匹配时,编译器会`预先检测是否有可能的匹配`,如果没有则报错。
    >
    > 3. 一个说明
    >
    > ~~~~scala
    > // case i : Int => i 表示 将 i = obj (其它类推),然后再判断类型
    > val result = obj match {
    > case i : Int => i
    > }
    > ~~~~
    >
    >
    >
    > 4. 如果 case _ 出现在match 中间,则表示隐藏变量名,即不使用,而不是表示默认匹配。

    #### 匹配数组

    > 1. Array(0) 匹配只有一个元素且为0的数组。
    > 2. Array(x,y) 匹配数组有两个元素,并将两个元素赋值为x和y。当然可以依次类推Array(x,y,z) 匹配数组有3个元素的等等....
    > 3. Array(0,_*) 匹配数组以0开始

    ~~~scala
    import scala.collection.mutable.ArrayBuffer

    /**
    * @Date 2021/4/3 16:14
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchArrDemo01 {
    def main(args: Array[String]): Unit = {

    // 这里arrs仅仅是一个数据
    val arrs = Array(
    Array(0), Array(1, 0),
    Array(0, 1, 0), Array(1, 1, 0),
    Array(1, 1, 0, 1)
    )

    // 遍历数据,arrs总共有五个元素
    for (arr <- arrs) {
    // 开始模式匹配
    val result = arr match {
    case Array(0) => "0"
    case Array(x, y) => x + " = " + y
    case Array(0, _*) => "以0开头和数组"
    case _ => "什么集合都不是"
    }

    /** 对结果分析:
    * result = 0
    * result = 1 = 0
    * result = 以0开头和数组
    * result = 什么集合都不是
    * result = 什么集合都不是
    */
    println("result = " + result)
    }

    println("--------------------匹配数组练习-------------------------")
    /**
    * 给你一个数组集合,如果该数组时 Array(10,20) , 请使用默认匹配,返回Array(20,10)
    */
    val arrs2 = Array(
    Array(0),
    Array(1, 0),
    Array(0, 1, 0), Array(1, 1, 0),
    Array(1, 1, 0, 1)
    )

    for (arr <- arrs2) {
    val result = arr match {
    case Array(x, y) => ArrayBuffer(y, x) //Array(y,x).toBuffer //? ArrayB(y,x)
    case _ => "不处理~~"
    }

    println("result = " + result) //ArrayBuffer(0,1)
    }
    }
    }
    ~~~

    #### 匹配列表

    ~~~~scala
    /**
    * @Date 2021/4/3 16:21
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchListDemo01 {
    def main(args: Array[String]): Unit = {
    val array = Array(
    List(0),
    List(1, 0),
    List(88),
    List(0, 0, 0), List(1, 0, 0)
    )

    for (list <- array) {

    // 进行模式匹配
    val result = list match {
    case 0 :: Nil => "0" //
    case x :: y :: Nil => x + " " + y

    // "以0开头的数组"
    case 0 :: tail => "0 ..." //
    case x :: Nil => x
    case _ => "something else"
    }

    /**
    * result = 0
    * result = 1 0
    * result = 88
    * result = 0 ...
    * result = something else
    */
    println("result = " + result)
    }
    }
    }
    ~~~~

    #### 匹配元组

    ~~~~scala
    /**
    * @Date 2021/4/3 16:27
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchTupleDemo01 {
    def main(args: Array[String]): Unit = {
    val array = Array((0, 1), (1, 0), (10, 30), (1, 1), (1, 0, 2))

    /**
    * 如果要匹配 (10, 30) 这样任意两个元素的对偶元组,应该如何写
    */
    for (pair <- array) {
    // 开始模式匹配
    val result = pair match {
    case (0, _) => "0 ..."
    case (y, 0) => y
    case (x, y) => (y, x) //"匹配到(x,y)" + x + " " + y
    case _ => "other"
    }

    /**
    * result = 0 ...
    * result = 1
    * result = (30,10)
    * result = (1,1)
    * result = other
    */
    println("result = " + result)
    }
    }
    }
    ~~~~

    #### 匹配对象

    > 对象匹配,什么才算是匹配呢?规则如下:
    >
    > case中对象的unapply方法(对象提取器)返回Some集合则为匹配成功,返回none集合则为匹配失败。
    >
    > 快速入门案例:

    ~~~~scala
    /**
    * @Date 2021/4/3 16:32
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchObjectDemo01 {
    def main(args: Array[String]): Unit = {
    val number: Double = Square(6.0)
    println(number)
    number match {
    /**
    * 说明 case Square(arg) 的运行的机制
    * 1. 当匹配到 case Square(arg)
    * 2. 调用Square 的 unapply(arg: Double),arg的值就是 number
    * 3. 如果对象提取器 unapply(arg: Double) 返回的是Some(6.0) ,
    * 则表示匹配成功,同时将6.0 赋给 Square(arg) 的 arg
    * 4. 果对象提取器 unapply(arg: Double) 返回的是None ,则表示匹配不成功
    */
    case Square(arg) => println(s"匹配成功arg = $arg")
    case _ => println("nothing matched")
    }
    }
    }

    object Square {
    /**
    * unapply方法是对象提取器
    *
    * @param arg 接收的Double类型的参数
    * @return 返回类型是Option[Double],
    * 返回值是Some(math.sqrt(arg)),返回arg的开平方的值并放入到Some()中
    */
    def unapply(arg: Double): Option[Double] = {
    Some(math.sqrt(arg))
    }

    def apply(arg: Double): Double = arg * arg
    }

    ~~~~

    > 应用案例二:

    ~~~scala
    /**
    * @Date 2021/4/3 16:48
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MatchObjectDemo2 {
    def main(args: Array[String]): Unit = {

    val namesString = "Alice,Bob,Thomas"
    // 开始模式匹配
    namesString match {
    /**
    * 当执行case Names(first, second, third)
    * 1. 会调用 unapplySeq(str),把 "Alice,Bob,Thomas" 传入给 str
    * 2. 如果 返回的是 Some("Alice","Bob","Thomas"),分别给 (first, second, third)
    * 注意,这里的返回的值的个数需要和 (first, second, third)要一样
    * 3. 如果返回的None ,表示匹配失败
    */
    case Names(first, second, third) => {
    // the string contains three people's names
    // Alice Bob Thomas
    println("the string contains three people's names")
    // 打印字符串
    println(s"$first $second $third")
    }
    case _ => println("nothing matched")
    }
    }
    }

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

    > 1. 当case 后面的对象提取器方法的参数为多个,则会默认调用`def unapplySeq()` 方法
    > 2. 如果`unapplySeq`返回是Some,获取其中的值,判断得到的sequence中的元素的个数是否是三个,如果是三个,则把三个元素分别取出,赋值给first,second和third
    > 3. 其它的规则不变。

    ### 3. 样例类

    > 1. 样例类仍然是类
    > 2. 样例类用case关键字进行声明。
    > 3. `样例类是为模式匹配而优化的类`。
    > 4. 构造器中的每一个参数都成为val——除非它被显式地声明为var(不建议这样做)
    > 5. 在样例类对应的伴生对象中提供apply方法让你不用new关键字就能构造出相应的对象提供unapply方法让模式匹配可以工作
    > 6. 将自动生成toString、equals、hashCode和copy方法(有点类似模板类,直接给生成,供程序员使用)
    > 7. 除上述外,样例类和其他类完全一样。你可以添加方法和字段,扩展它们。

    #### 样例类快速入门

    ~~~~scala
    package com.atguigu.chapter12.caseclass

    /**
    * @Date 2021/4/3 17:23
    * @Version 10.21
    * @Author DuanChaojie
    */
    object CaseClassDemo01 {
    def main(args: Array[String]): Unit = {
    println("-------------------------------")

    /**
    * 类型(对象)--序列化---字符串:
    * 1.可以保存到文件中
    * 2.反序列化
    * 3.网络传输
    */
    }
    }

    abstract class Amount

    /**
    * 样例类
    * @param value
    */
    case class Dollar(value: Double) extends Amount

    /**
    * 样例类
    * @param value
    * @param unit
    */
    case class Currency(value: Double, unit: String) extends Amount

    /**
    * 样例类
    */
    case object NoAmount extends Amount
    ~~~~

    #### 样例类最佳实践

    > 样例类最佳实践一:当我们有一个类型为Amount的对象时,可以用模式匹配来匹配他的类型,并将属性值绑定到变量(即:把样例类对象的属性值提取到某个变量,该功能有用)

    ~~~~scala
    package com.atguigu.chapter12.caseclass

    /**
    * @Date 2021/4/3 18:15
    * @Version 10.21
    * @Author DuanChaojie
    */
    object CaseClassDemo02 {
    def main(args: Array[String]): Unit = {
    val array = Array(Dollar2(1000.0), Currency2(1000.0, "RMB"), NoAmount2)
    for (amt <- array) {
    val result = amt match {
    case Dollar2(v) => "$" + v
    case Currency2(v, u) => v + " " + u
    case NoAmount2 => ""
    }
    println("amt = " + amt)
    println("result =" + result)
    }
    }
    }

    abstract class Amount2

    /**
    * 样例类
    *
    * @param value
    */
    case class Dollar2(value: Double) extends Amount2

    /**
    * 样例类
    *
    * @param value
    * @param unit
    */
    case class Currency2(value: Double, unit: String) extends Amount2

    /**
    * 样例类
    */
    case object NoAmount2 extends Amount2
    ~~~~

    > 样例类最佳实践二:
    >
    > 1. 样例类的copy方法和带名参数
    > 2. copy创建一个与现有对象值相同的新对象,并可以通过带名参数来修改某些属性。

    ~~~~scala
    /**
    * @Date 2021/4/3 18:30
    * @Version 10.21
    * @Author DuanChaojie
    */
    object CaseClassDemo03 {
    def main(args: Array[String]): Unit = {
    val amt1 = new Currency3(3000.0, "RMB")
    // 克隆,创建的对象和amt的属性一样
    val amt2 = amt1.copy()

    // amt2.value = Currency3(3000.0,RMB).value amt2.unit = Currency3(3000.0,RMB).unit
    println(s"amt2.value = $amt2.value \t amt2.unit = $amt2.unit")

    val amt3 = amt1.copy(value = 8000.0)
    // amt3 = Currency3(8000.0,RMB)
    println("amt3 = " + amt3)

    val amt4 = amt1.copy(unit = "美元")
    // amt4 = Currency3(3000.0,美元)
    println("amt4 = " + amt4)
    }
    }

    abstract class Amount3

    /**
    * 样例类
    *
    * @param value
    */
    case class Dollar3(value: Double) extends Amount3

    /**
    * 样例类
    *
    * @param value
    * @param unit
    */
    case class Currency3(value: Double, unit: String) extends Amount3

    /**
    * 样例类
    */
    case object NoAmount3 extends Amount3
    ~~~~

    #### case语句的中置(缀)表达式

    > 什么是中置表达式?1 + 2,这就是一个中置表达式。如果unapply方法产出一个元组,你可以在case语句中使用中置表示法。比如可以匹配一个List序列

    ~~~~scala
    /**
    * @Date 2021/4/3 18:38
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MidCase {
    def main(args: Array[String]): Unit = {
    List(1, 3, 5, 9) match {
    /**
    * 修改并测试
    * 1.两个元素间::叫中置表达式,至少first,second两个匹配才行.
    * 2.first 匹配第一个 second 匹配第二个, rest 匹配剩余部分(5,9)
    */
    case first :: second :: rest => println(first + " " + second + "\nrest.length = "+ rest.length + "\n" + rest) //
    case _ => println("匹配不到...")
    }
    }
    }
    ~~~~

    #### 匹配嵌套结构

    > 操作原理类似于正则表达式
    >
    > 最佳实践案例——商品捆绑打折出售
    >
    > 1. 现在有一些商品,请使用Scala设计相关的样例类,完成商品捆绑打折出售。
    > 2. 要求商品捆绑可以是单个商品,也可以是多个商品。
    > 3. 打折时按照折扣x元进行设计
    > 4. 能够统计出所有捆绑商品打折后的最终价格。
    >
    > 样例类的设计:

    ~~~~scala
    /**
    * 设计样例类
    */
    abstract sealed class Item

    case class Book(description: String, price: Double) extends Item

    case class Food(description: String, price: Double) extends Item

    /**
    * Bundle 捆 , discount: Double 折扣 , item: Item*
    *
    * @param description 描述
    * @param discount 折扣的价格
    * @param item
    */
    case class Bundle(description: String, discount: Double, item: Item*) extends Item
    ~~~~

    > 完成这个案例需要有以下知识储备:
    >
    > 1. 如果我们进行对象匹配时,不想接受某些值,则使用_ 忽略即可,_* 表示所有
    > 2. 通过@表示法将嵌套的值绑定到变量。_*绑定剩余Item到rest
    > 3. 不使用_*绑定剩余Item到rest

    ~~~~scala
    /**
    * @Date 2021/4/3 18:43
    * @Version 10.21
    * @Author DuanChaojie
    */
    object CaseClassExercise {
    def main(args: Array[String]): Unit = {
    /**
    * 这里给出了一个具体的打折的案例
    */
    val sale = Bundle("书籍", 10, Book("漫画", 40),
    Bundle("文学作品", 20, Book("《阳关》", 80), Book("《围城》", 30), Book("天龙八部", 100)))

    /** 完成上面例子之前需要学习三个知识点:
    * 知识点1 :使用case语句,得到 "漫画"
    */
    val res1 = sale match {
    /**
    * 如果我们进行对象匹配时,不想接受某些值,则使用_ 忽略即可,_* 表示所有
    */
    case Bundle(_, _, Book(desc, _), _*) => desc
    }
    // res1 = 漫画
    println("res1 = " + res1)

    /**
    * 知识点2-通过@表示法将嵌套的值绑定到变量。_*绑定剩余Item到rest
    */
    val res2 = sale match {
    //如果我们进行对象匹配时,不想接受某些值,则使用_ 忽略即可,_* 表示所有
    case Bundle(_, _, art@Book(_, _), rest@_*) => (art, rest)
    }
    // res2 = (Book(漫画,40.0),WrappedArray(Bundle(文学作品,20.0,WrappedArray(Book(《阳关》,80.0), Book(《围城》,30.0), Book(天龙八部,100.0)))))
    println("res2 = " + res2)


    /**
    * 知识点3-不使用_*绑定剩余Item到rest
    */
    val res3 = sale match {
    // 如果我们进行对象匹配时,不想接受某些值,则使用_ 忽略即可,_* 表示所有
    case Bundle(_, _, art3@Book(_, _), rest3) => (art3, rest3)
    }
    // res3 = (Book(漫画,40.0),Bundle(文学作品,20.0,WrappedArray(Book(《阳关》,80.0), Book(《围城》,30.0), Book(天龙八部,100.0))))
    println("res3 = " + res3)
    }
    }
    ~~~~

    > 完成上面的案例:

    ~~~scala
    /**
    * @Date 2021/4/3 18:43
    * @Version 10.21
    * @Author DuanChaojie
    */
    object CaseClassExercise {
    def main(args: Array[String]): Unit = {
    /**
    * 这里给出了一个具体的打折的案例
    */
    val sale = Bundle("书籍", 10, Book("漫画", 40),
    Bundle("文学作品", 20, Book("《阳关》", 80), Book("《围城》", 30), Book("天龙八部", 100)))

    /**
    * 完成案例
    * price(sale) = 220.0
    */
    println("price(sale) = " + price(sale))

    }

    def price(it: Item): Double = {
    it match {
    case Book(_, p) => p
    case Bundle(_, disc, its@_*) => its.map(price).sum - disc
    }
    }
    }
    ~~~

    ### 4. 密闭类

    > 1. 如果想让case类的所有子类都必须在申明该类的相同的源文件中定义,可以将样例类的通用超类声明为sealed,这个超类称之为密封类。
    > 2. 密封就是不能在其他文件中定义子类。
    > 3. ![image-20210403200246976](assets/image-20210403200246976.png)

    ## ☆

  • 相关阅读:
    Fox Dividing Cheese [CF-371B]
    2021计算机专业方向志愿怎么填?哪一个更香?
    【每天一个编程小技巧】C++ return:使函数立即结束!
    我开发了一个女朋友陪聊系统!【全天24小时推送问候,自动回复女友的微信消息】
    【C++框架编程】Qt 的 信号与槽 简单了解!
    程序人生:一流靠数学,二流靠算法!程序员的数学需要很厉害吗?
    【硬核知识】C语言文件操作!文件的打开和关闭!
    程序员真的已经没救了吗?这可能就是前端鄙视后端的真正原因吧!
    刷题 678 天的感受!Coding使我快乐,bug使我憔悴!
    MQ面试题
  • 原文地址:https://www.cnblogs.com/huaobin/p/15764430.html
Copyright © 2011-2022 走看看