• Scala 模式匹配和样例类+协变、逆变、非变+上下界


    1.   模式匹配和样例类

    Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句、类型检查等。并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配。

    1.1.   匹配字符串

    package com.gec.cases
    import scala.util.Random

    object CaseDemo01 extends App{
      val arr = Array("hadoop", "zookeeper", "spark")
      val name = arr(Random.nextInt(arr.length))
      name match {
        case "hadoop"    => println("大数据分布式存储和计算框架...")
        case "zookeeper" => println("大数据分布式协调服务框架...")
        case "spark" => println("大数据分布式内存计算框架...")
        case _ => println("我不认识你...")
      }
    }
     

    1.2.   匹配类型

    package com.gec.cases
    import scala.util.Random

    object CaseDemo02 extends App{
     
    val arr = Array("hello", 1, 2.0, CaseDemo)
      val v = arr(Random.nextInt(4))
      println(v)
      v match {
        case x: Int => println("Int " + x)
        case y: Double if(y >= 0) => println("Double "+ y)
        case z: String => println("String " + z)
        case _ => throw new Exception("not match exception")
      }
    }
     

    注意case y: Double if(y >= 0) => ...

    模式匹配的时候还可以添加守卫条件。如不符合守卫条件,将掉入case _中。

    1.3.   匹配数组、元组、集合

    package com.gec.cases

    object CaseDemo03 extends App{

      val arr = Array(1, 3, 5)
      arr match {
        case Array(1, x, y) => println(x + " " + y)
        case Array(0) => println("only 0")
        case Array(0, _*) => println("0 ...")
        case _ => println("something else")
      }

      val lst = List(3, -1)
      lst match {
        case 0 :: Nil => println("only 0")
        case x :: y :: Nil => println(s"x: $x y: $y")
        case 0 :: tail => println("0 ...")
        case _ => println("something else")
      }

      val tup = (1, 3, 7)
      tup match {
        case (1, x, y) => println(s"1, $x , $y")
        case (_, z, 5) => println(z)
        case  _ => println("else")
      }
    }
     

    注意:在Scala中列表要么为空(Nil表示空列表)要么是一个head元素加上一个tail列表。

    9 :: List(5, 2)  :: 操作符是将给定的头和尾创建一个新的列表

    注意::: 操作符是右结合的,如9 :: 5 :: 2 :: Nil相当于 9 :: (5 :: (2 :: Nil))

    1.4.   样例类

    在Scala中样例类是一种特殊的类,可用于模式匹配。

    定义形式:

    case class 类型,是多例的,后面要跟构造参数。 case class Student(name:String)

    case object 类型,是单例的。        case object Person

    package com.gec.cases
    import scala.util.Random

    case class SubmitTask(id: String, name: String)
    case class HeartBeat(time: Long)
    case object CheckTimeOutTask

    object CaseDemo04 extends App{
      val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))

      arr(Random.nextInt(arr.length)) match {
        case SubmitTask(id, name) => {
          println(s"$id, $name")
        }
        case HeartBeat(time) => {
          println(time)
        }
        case CheckTimeOutTask => {
          println("check")
        }
      }
    }
     

    1.5.   Option类型

    在Scala中Option类型用样例类来表示可能存在或者可能不存在的值(Option的子类有Some和None)。Some包装了某个值,None表示没有值

    package com.gec.cases

    object OptionDemo {
      def main(args: Array[String]) {
        val map = Map("a" -> 1, "b" -> 2)
        val v = map.get("b") match {
          case Some(i) => i
          case None => 0
        }
        println(v)
        //更好的方式
       
    val v1 = map.getOrElse("c", 0)
        println(v1)
      }
    }
     

    1.6.   偏函数

    被包在花括号内没有match的一组case语句是一个偏函数,它是PartialFunction[A, B]的一个实例,A代表输入参数类型,B代表返回结果类型,常用作输入模式匹配,偏函数最大的特点就是它只接受和处理其参数定义域的一个子集。

    package com.gec.cases

    object PartialFuncDemo  {

      valfunc1: PartialFunction[String, Int] = {
        case "one" => 1
        case "two" => 2
        case _ => -1
      }

      def func2(num: String) : Int = num match {
        case "one" => 1
        case "two" => 2
        case _ => -1
      }

      def main(args: Array[String]) {
        println(func1("one"))
        println(func2("one"))
      }
    }

    2.    Scala中的协变、逆变、非变

    2.1.   协变、逆变、非变介绍

    Array[int]     Array[Object]  

    协变和逆变主要是用来解决参数化类型的泛化问题。Scala的协变与逆变是非常有特色的,完全解决了Java中泛型的一大缺憾;举例来说,Java中,如果有 A是 B的子类,但 Card[A] 却不是 Card[B] 的子类;而 Scala 中,只要灵活使用协变与逆变,就可以解决此类 Java 泛型问题;

    由于参数化类型的参数(参数类型)是可变的,当两个参数化类型的参数是继承关系(可泛化),那被参数化的类型是否也可以泛化呢?Java中这种情况下是不可泛化的,然而Scala提供了三个选择,即协变(“+”)、逆变(“-”)和非变。

    下面说一下三种情况的含义,首先假设有参数化特征Queue,那它可以有如下三种定义。

    (1)  trait Queue[T] {}

    这是非变情况。这种情况下,当类型B是类型A的子类型,则Queue[B]与Queue[A]没有任何从属关系,这种情况是和Java一样的。

    (2)  trait Queue[+T] {} 
             这是协变情况。这种情况下,当类型B是类型A的子类型,则Queue[B]也可以认为是Queue[A]的子类型,即Queue[B]可以泛化为Queue[A]。也就是被参数化类型的泛化方向与参数类型的方向是一致的,所以称为协变。

    (3)   trait Queue[-T] {} 

    这是逆变情况。这种情况下,当类型B是类型A的子类型,则Queue[A]反过来可以认为是Queue[B]的子类型。也就是被参数化类型的泛化方向与参数类型的方向是相反的,所以称为逆变。 

    2.2.   协变、逆变、非变总结

    • C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。
    • C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。
    • C[T]: 无论A和B是什么关系,C[A]和C[B]没有从属关系。

    2.3.   案例


    package com.gec.scala.enhance.covariance


    class Super
    class Sub extends Super
    //协变
    class Temp1[+A](title: String)
    //逆变
    class Temp2[-A](title: String)
    //非变
    class Temp3[A](title: String)

    object Covariance_demo{
      def main(args: Array[String]) {
        //支持协变 Temp1[Sub]还是Temp1[Super]的子类
        val t1: Temp1[Super] = new Temp1[Sub]("hello scala!!!")
        //支持逆变 Temp1[Super]是Temp1[Sub]的子类
        val t2: Temp2[Sub] = new Temp2[Super]("hello scala!!!")
        //支持非变 Temp3[Super]与Temp3[Sub]没有从属关系,如下代码会报错
        //val t3: Temp3[Sub] = new Temp3[Super]("hello scala!!!")
    //val t4: Temp3[Super] = new Temp3[Sub]("hello scala!!!")
        println(t1.toString)
        println(t2.toString)
      }
    }

    3.    Scala中的上下界

    3.1.  上界、下界介绍

    在指定泛型类型时,有时需要界定泛型类型的范围,而不是接收任意类型。比如,要求某个泛型类型,必须是某个类的子类,这样在程序中就可以放心的调用父类的方法,程序才能正常的使用与运行。此时,就可以使用上下边界Bounds的特性;

    Scala的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类;

     

     

    (1) U >: T     ?  super  T

     

    这是类型下界的定义,也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)。

     

    (2) S <: T    ?  extends T

     

    这是类型上界的定义,也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类)。

  • 相关阅读:
    1015: [JSOI2008]星球大战starwar
    Tyvj P1813 [JSOI2008]海战训练
    1012: [JSOI2008]最大数maxnumber
    1430: 小猴打架
    1270: [BeijingWc2008]雷涛的小猫
    1202: [HNOI2005]狡猾的商人
    1059: [ZJOI2007]矩阵游戏
    3039: 玉蟾宫
    1303: [CQOI2009]中位数图
    1002: [FJOI2007]轮状病毒
  • 原文地址:https://www.cnblogs.com/Transkai/p/10968885.html
Copyright © 2020-2023  润新知