“将欲歙之,必固张之;将欲弱之,必固强之;将欲废之,必固举之;将欲取之,必固予之。
是谓微明。
柔弱胜刚强。
鱼不可脱于渊,国之利器不可以示人。”1
模式匹配
关于scala的模式匹配在上篇博客《从java(python)到scala的n种记忆》中有提及,但是模式匹配在scala中应用的地方太多了,有必要单独攒一篇文字来记录它。
模式匹配跟java中的switch-case绝对的相似,只是java中只能匹配值,而scala中的这个不仅能匹配值,而且可以匹配类型和类。
按值匹配
1def bigData(content:String):Unit = {2content match{3case "spark" => println("yeah!spark!")4case "kafka" => println("wow!kafka!")5case _ => println("anything else?")6}7}8def main(args: Array[String]) {9bigData("spark")10bigData("kafka")11bigData("zipkin")12}输出:
1yeah!spark!2wow!kafka!3anything else?case 后面还可以加条件判断,不过貌似不会很常用。
类型模式匹配
1object Demo {2def main(args: Array[String]) {3println(matchTest("two"))4println(matchTest("test"))5println(matchTest(1))6}78def matchTest(x: Any): Any = x match {9case 1 => "one"10case "two" => 211case y: Int => "scala.Int"12case _ => "many"13}14}输出:
122many3one样例类(case class)模式匹配
ScalaCase类只是常规类,默认情况下是不可变的,可通过模式匹配可分解。它使用相等(equal)方法在结构上比较实例。它不使用new关键字实例化对象。默认情况下,case类中列出的所有参数默认使用public和immutable修辞符。
语法:1case class className(parameters)1case class CaseClass(a:Int, b:Int)23object Demo{4def main(args:Array[String]){5var c = CaseClass(13,14) // Creating object of case class6println("a = "+c.a) // Accessing elements of case class7println("b = "+c.b)8}9}输出:
1a = 132b = 14Case类支持模式匹配。 所以,可以在模式中使用它。没有参数的case类将被声明为case对象而不是case类。 默认情况下,case对象是
可序列化的。1trait SuperTrait2case class CaseClass1(a:Int,b:Int) extends SuperTrait3case class CaseClass2(a:Int) extends SuperTrait // Case class4case object CaseObject extends SuperTrait // Case object5object Demo{6def main(args:Array[String]){7callCase(CaseClass1(10,10))8callCase(CaseClass2(10))9callCase(CaseObject)10}11def callCase(f:SuperTrait) = f match{12case CaseClass1(f,g)=>println("a = "+f+" b ="+g)13case CaseClass2(f)=>println("a = "+f)14case CaseObject=>println("No Argument")15}16}输出:
1a = 10 b =102a = 103No Argument类型参数
Scala中的类型参数,与java中的泛型类似。
1class Person[T](val content:T){2def getContent(id:T)=id+"_"+content3}4……5def main(args: Array[String]) {6val person_Str = new Person[String]("String")7println(person_Str.getContent("spark"))8val person_Int = new Person[Int](14)9println(person_Int.getContent(13))10}输出:
1spark_String213_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:老子《道德经》第三十六章,老子故里,中国鹿邑。