Scala基础 -- 5.模式匹配、样例类、协变逆变非变和上下界

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

5.1 模式匹配

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

5.1.1 匹配字符串
val arr = Array("hadoop", "storm", "spark", "zookeeper")
val name = arr(Random.nextInt(arr.length))
name match {
    case "hadoop" => println("大数据分布式存储和计算框架")
    case "zookeeper" => println("大数据分布式协调服务框架")
    case "spark" => println("大数据分布式内存计算框架")
    case _ => println("我不认识你...")
}
5.1.2 匹配类型
val arr1 = Array("hello", 1, 2.0, true, ScalaTest5_1)
val r1 = arr1(Random.nextInt(arr1.length))
println(r1)
r1 match {
    case x: Int => print("Int " + x)
    case y: Double if(y >=0 ) => println("Double " + y)
    case z: String => println("String " + z)
    case _ => throw new Exception("not match exception")
}
5.1.3 匹配数组
val arr2 = Array(1, 2, 3)
arr2 match {
    //匹配数组只有三个长度,并且头为1
    case Array(1, x, y) => println(x + ", " + y)
    //匹配数组长度为1,且元素为0
    case Array(0) => println("only 0")
    //匹配数组头为1,长度不限制
    case Array(0, _*) => println("start with 0")
    case _ => println("something else")
}
5.1.4 匹配元组
val tuple = (1,2,3)
tuple match {
    //匹配三个元素的元组,并且第一个元素为1
    case (1, x, y) => println(s"1, $x, $y")
    //匹配三个元素的元组,并且第三个元素为5
    case (_, z, 5) => println(z)
    case _ => println("else")
}
5.1.5 匹配集合
val list = List(1, 2, -1)
list match {
    //匹配长度为1的List,并且元素为0
    case 0 :: Nil => println("only 0")
    //匹配长度为2的List
    case x :: y :: Nil => println(s"x: $x, y: $y")
    //匹配头为0,长度不限制的List
    case 0 :: tail => println("start with 0")
    case _ => println("something else")
}

5.2 样例类和Option类型

object ScalaTest5_2{
    /**
      * 在Scala中样例类是一种特殊的类,可用于模式匹配。定义形式:
      * case class 类型,是多例的,后面要跟构造参数。
      * case object 类型,是单例的。
      */
    def main(args: Array[String]): Unit = {
        val arr = Array(CheckTimeOut, HeartBeat(1000), SubmitTask("11", "task-1"))
        arr(Random.nextInt(arr.length)) match {
            case SubmitTask(id: String, name: String) => println(s"id: $id, name: $name")
            case HeartBeat(time: Long) => println(s"time: $time")
            case CheckTimeOut => println("CheckTimeOut")
            case _ => println("something else")
        }

        /**
          * 在Scala中Option类型用样例类来表示可能存在或者可能不存在的值(Option的子类有Some和None)。
          * Some包装了某个值,None表示没有值
          */
        val map = Map("a" -> 1, "b" -> 2)
        val v = map.get("c") match {
            case Some(i) => i
            case None => 0
        }
        println(v)
        //也可以
        println(map.getOrElse("c", 0))
    }
}
case class SubmitTask(id: String, name: String)
case class HeartBeat(time: Long)
case object CheckTimeOut

5.3 偏函数

/**
  * 被包在花括号内没有match的一组case语句是一个偏函数,它是PartialFunction[A, B]的一个实例
  * A代表输入参数类型,B代表返回结果类型,常用作输入模式匹配
  * 偏函数最大的特点就是它只接受和处理其参数定义域的一个子集
  */
//偏函数必须指定PartialFunction,并且参数给定输入和输出类型
def fun1: PartialFunction[String, Int] = {
    case "one" => 1
    case "two" => 2
    case _ => -1
}
//fun2是普通方法模拟偏函数
def fun2(num: String) : Int = num match {
    case "one" => 1
    case "two" => 2
    case _ => -1
}
def main(args: Array[String]): Unit = {
    println(fun1("two"))
    println(fun2("one"))
}

5.4 协变、逆变、非变

  协变和逆变主要是用来解决参数化类型的泛化问题。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]的子类型。也就是被参数化类型的泛化方向与参数类型的方向是相反的,所以称为逆变。

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

object ScalaTest5_4{
    def main(args: Array[String]): Unit = {
        //支持协变 Temp1[Sub]还是Temp1[Super]的子类
        val t1: Temp1[Super] = new Temp1[Sub]("Hello World")
        println(t1.toString)

        //支持逆变 Temp1[Super]是Temp1[Sub]的子类
        val t2: Temp2[Sub] = new Temp2[Super]("Hello World")
        println(t2.toString)

        //支持非变 Temp3[Super]与Temp3[Sub]没有从属关系,如下代码会报错
//        val t3: Temp3[Super] = new Temp3[Sub]("Hello World")
//        val t4: Temp3[Sub] = new Temp3[Super]("Hello World")
    }
}
class Super
class Sub extends Super
//协变
class Temp1[+A](title: String)
//逆变
class Temp2[-A](title: String)
//非变
class Temp3[A](title: String)

5.5 上、下界

  在指定泛型类型时,有时需要界定泛型类型的范围,而不是接收任意类型。比如,要求某个泛型类型,必须是某个类的子类,这样在程序中就可以放心的调用父类的方法,程序才能正常的使用与运行。此时,就可以使用上下边界Bounds的特性;
  Scala的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类;
(1) U >: T
  定义类型下界,也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)。
(2) S <: T
  定义类型上界,也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值