0%

scala模式匹配和类型参数

“将欲歙之,必固张之;将欲弱之,必固强之;将欲废之,必固举之;将欲取之,必固予之。
是谓微明。
柔弱胜刚强。
鱼不可脱于渊,国之利器不可以示人。”1

模式匹配

关于scala的模式匹配在上篇博客《从java(python)到scala的n种记忆》中有提及,但是模式匹配在scala中应用的地方太多了,有必要单独攒一篇文字来记录它。

模式匹配跟java中的switch-case绝对的相似,只是java中只能匹配值,而scala中的这个不仅能匹配值,而且可以匹配类型和类。

  • 按值匹配

    1
    def bigData(content:String):Unit = {
    2
        content match{
    3
            case "spark" => println("yeah!spark!")
    4
            case "kafka" => println("wow!kafka!")
    5
            case _ => println("anything else?")
    6
        }
    7
      }
    8
    def main(args: Array[String]) {
    9
        bigData("spark")
    10
        bigData("kafka")
    11
        bigData("zipkin")
    12
      }

    输出:

    1
    yeah!spark!
    2
    wow!kafka!
    3
    anything else?

    case 后面还可以加条件判断,不过貌似不会很常用。

  • 类型模式匹配

    1
    object Demo {
    2
       def main(args: Array[String]) {
    3
          println(matchTest("two"))
    4
          println(matchTest("test"))
    5
          println(matchTest(1))
    6
       }
    7
    8
       def matchTest(x: Any): Any = x match {
    9
          case 1 => "one"
    10
          case "two" => 2
    11
          case y: Int => "scala.Int"
    12
          case _ => "many"
    13
       }
    14
    }

    输出:

    1
    2
    2
    many
    3
    one
  • 样例类(case class)模式匹配
    Scala Case类只是常规类,默认情况下是不可变的,可通过模式匹配可分解。它使用相等(equal)方法在结构上比较实例。它不使用new关键字实例化对象。默认情况下,case类中列出的所有参数默认使用public和immutable修辞符。
    语法:

    1
    case class className(parameters)
    1
    case class CaseClass(a:Int, b:Int)  
    2
    3
    object Demo{  
    4
        def main(args:Array[String]){  
    5
            var c =  CaseClass(13,14)       // Creating object of case class  
    6
            println("a = "+c.a)               // Accessing elements of case class  
    7
            println("b = "+c.b)  
    8
        }  
    9
    }

    输出:

    1
    a = 13
    2
    b = 14

    Case类支持模式匹配。 所以,可以在模式中使用它。没有参数的case类将被声明为case对象而不是case类。 默认情况下,case对象是可序列化的。

    1
    trait SuperTrait  
    2
    case class CaseClass1(a:Int,b:Int) extends SuperTrait  
    3
    case class CaseClass2(a:Int) extends SuperTrait         // Case class  
    4
    case object CaseObject extends SuperTrait               // Case object  
    5
    object Demo{  
    6
        def main(args:Array[String]){  
    7
            callCase(CaseClass1(10,10))  
    8
            callCase(CaseClass2(10))  
    9
            callCase(CaseObject)  
    10
        }  
    11
        def callCase(f:SuperTrait) = f match{  
    12
            case CaseClass1(f,g)=>println("a = "+f+" b ="+g)  
    13
            case CaseClass2(f)=>println("a = "+f)  
    14
            case CaseObject=>println("No Argument")  
    15
        }  
    16
    }

    输出:

    1
    a = 10 b =10
    2
    a = 10
    3
    No Argument

    类型参数

    Scala中的类型参数,与java中的泛型类似。

    1
    class Person[T](val content:T){
    2
      def getContent(id:T)=id+"_"+content
    3
    }
    4
    ……
    5
    def main(args: Array[String]) {
    6
        val person_Str = new Person[String]("String")
    7
        println(person_Str.getContent("spark"))
    8
        val person_Int = new Person[Int](14)
    9
        println(person_Int.getContent(13))
    10
      }

    输出:

    1
    spark_String
    2
    13_14

    所以,我们使用类型参数,可以很好的指定特定值得输入类型,然后基于该类型进行一些操作,增加了程序的健壮性。Spark中的RDD就是这样的。
    上面只是一个简单的例子,scala的泛型[T]有如下六种方式:

  • scala的类和方法、函数都可以是泛型。

  • 关于对类型边界的限定分为上边界和下边界(对类进行限制)
    上边界:表达了泛型的类型必须是某种类型或者某种类的子类,语法为<:,例如T <: AnyVal表示泛型T的类型的最顶层类是AnyVal。
    下边界:表达了泛型的类型必须是某种类型或者某种类的父类,语法为>:,例如T >: S表示泛型T的类型必须是S的超类,下界的作用主要是保证类型安全。

  • “<%” :view bounds可以进行某种神秘的转换,把你的类型在没有知觉的情况下转换成目标类型
    如果希望类型变量界定能跨越类继承层次结构时,可以使用视图界定来实现的,其后面的原理是通过隐式转换来实现。视图界定利用<%符号来实现,例如后面的例子[T <% Person],T是Person继承的或者是能变成Person。

  • “T:classTag”:相当于动态类型,你使用时传入什么类型就是什么类型

  • 逆变和协变:-T和+T
    逆变和协变最容易理解的便是用List来理解。
    协变定义形式如:trait List[+T] {} 。当类型S是类型A的子类型时,则List[S]也可以认为是List[A}的子类型,
    即List[S]可以泛化为List[A]。
    逆变定义形式如:trait List[-T] {}
    当类型S是类型A的子类型,则Queue[A]反过来可以认为是Queue[S}的子类型。

  • “T:Ordering” :表示将T变成Ordering[T],可以直接用其方法进行比大小,可完成排序等工作

1:老子《道德经》第三十六章,老子故里,中国鹿邑。