第41讲:List继承体系实现内幕和方法操作源码揭秘
def main(args: Array[String]) {
/**
* List继承体系实现内幕和方法操作源码揭秘
*
* List本身是一个抽象类 定义如下:
* abstract sealed class List[+A] extends AbstractSeq[A]
* with LinearSeq[A]
* with Product
* with GenericTraversableTemplate[A, List]
* with LinearSeqOptimized[A, List[A]]
*
* List下的两个重要的子类Nil和::
* Nil 表示一个空值 定义为一个Cass Object: case object Nil extends List[Nothing]
* :: 定义 final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extends List[B]
*
*/
//这种方式其实是 调用List的伴生对象的apply方法 val list: List[Int]
val list: List[Int] = List(1, 2, 3, 4, 5)
//这是一种"协变"的概念 Int为Any的子类 所以认为List[Int]的具体父类型可以是List[Any]
val listAny: List[Any] = list
println(list.isEmpty)
println(list.head)
println(list.tail)
println(list.length)
println(list.drop(2))
list.map(_ * 2)
}
第42讲:Scala中泛型类、泛型函数、泛型在Spark中的广泛应用
/**
* 定义一个泛型类[]中定义的就是未知的类型 只有赋值使用才能确定具体的类型
*/
class Triple[F, S, T](val first: F, val second: S, val third: T)
/**
* Scala中泛型类、泛型函数、泛型在Spark中的广泛应用
*/
object Hello_Type_Parameterization {
def main(args: Array[String]) {
//在定义后scala的类型推断会得出triple类型为 Triple[String, Int, Double]
val triple = new Triple("Spark", 3, 3.1415)
//显示声明类型
val bigData = new Triple[String, String, Char]("Spark", "Hadoop", 'R')
//定义泛型类型
def getData[T](list : List[T]) = list(list.length / 2)
//List(1)=>"Hadoop"
println(getData(List("Spark", "Hadoop", 'R')))
val f = getData[Int] _
println(f(List(1,2,3,4,5,6)))//5
val queue = Queue(1,2,3,4,5)
val queue_appended = queue enqueue 6
println("queue : " + queue + " " + "queue_appended : " + queue_appended)
}
}
第43讲:Scala中类型变量Bounds代码实战及其在Spark中的应用源码解析
/**
* 类型的界定
* 这里的[T <: Comparable[T]] 表示类型T必须是Comparable[T]的子类
*/
class Pair[T <: Comparable[T]](val first : T,val second : T){
def bigger = if(first.compareTo(second) > 0)first else second
}
/**
* [R >: T]表示 R类型是T类型的父类
* 类型变量的界定 就R而言 T为R的下界 就T而言 R为T的上界
*
*/
class Pair_Lower_Bound[T](val first:T,val second:T){
def replaceFirst[R >: T](newFirst:R)= new Pair_Lower_Bound[R](newFirst,second)
}
object Typy_Variables_Bounds {
def main(args: Array[String]){
/**
* 49-57:0-9
* A-Z:66-90
* a-z:97-122
*/
val schar='S'
println(schar.toInt)
println('H'.toInt)
println("Spark".compareTo("Hadoop"))//11
val pair = new Pair("Spark", "Hadoop")
println(pair.bigger)//Spark
}
}
第44讲:Scala中View Bounds代码实战及其在Spark中的应用源码解析
class Pair_NotPerfect2[T <: Comparable[T]](val first : T,val second : T){
def bigger = if(first.compareTo(second) > 0)first else second
}
/**
* 视图界定 <%
*/
/**
* Ordered视图界定
* 上面这种方式的12行first.compareTo(second) > 0 通过compareTo来比较 但是不能直观的像数学比较那样清晰
* Scala提供了Ordered视图界定
* Ordered在Comparable上提供一些关系型的操作符 < > <= >=等
*/
class Pair_NotPerfect[T <% Comparable[T]](val first : T,val second : T){
def bigger = if(first.compareTo(second) > 0)first else second
}
class Pair_Better[T <% Ordered[T]](val first : T,val second : T){
def bigger = if(first > second)first else second
}
object View_Bounds {
def main(args: Array[String]) {
// val pair2 = new Pair_NotPerfect2(1, 3)
// println(pair2.bigger)
val pair = new Pair_NotPerfect("Spark", "Hadoop")
println(pair.bigger)
/*
* 当类型界定为Pair_NotPerfect[T <: Comparable[T]]报错 因为Int本身不是Comparable的子类
*
* 当类型界定为视图界定时 Pair_NotPerfect[T <% Comparable[T]] 就可以正常运行
* 是因为Int本身不是Comparable的子类型 Scala通过"隐式转换"将Int转换成RichInt 而这个类型是Comparable的子类
*/
val pairInt = new Pair_NotPerfect(3, 5) //Int -> RichInt
println(pairInt.bigger)
/**
* 注意:这样定义不是因为String的上界是Ordered[String],String不是Ordered[String]的子类
* 当使用视图界定时 会发生"隐式转换" 把String --> RichString
* 而RichString是Ordered[RichString]的子类型 RichString中是实现了这样的 < > <= >=等方法
* 从而真正是让String类型完成视图界定
*/
val pair_Better_String = new Pair_Better("Java", "Scala") //String -> RichString
println(pair_Better_String.bigger)
val pair_Better_Int = new Pair_Better(20, 12)
println(pair_Better_Int.bigger)
}
}
第45讲:Scala中Context Bounds代码实战及其在Spark中的应用源码解析
/**
* 上下文界定 [T : Ordering] 说明存在一个隐式的值Ordering[T] //implicit ordered: Ordering[T]
*
* Ordering源码声明:
* trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with Serializable
*/
class Pair_Ordering[T : Ordering] (val first : T, val second : T){
//这是一个隐式转换的显式定义 这个函数没有参数 当时函数执行的时候 这个隐式值就会自动传进来
def bigger(implicit ordered: Ordering[T]) = {
if (ordered.compare(first, second) > 0) first else second
}
}
object Context_Bounds {
def main(args: Array[String]) {
val pair = new Pair_Ordering("Spark", "Hadoop")
println(pair.bigger)
val pairInt = new Pair_Ordering(3, 5)
println(pairInt.bigger)
}
}
第46讲: ClassTag 、Manifest、ClassManifest、TypeTag代码实战及其在Spark中的应用源码解析
package com.wanji.scala.type_parameterization
import scala.reflect.ClassTag
class A[T]
/**
* ClassTag 、Manifest、ClassManifest、TypeTag代码实战及其在Spark中的应用源码解析
*
* ClassTag ==> ClassManifest
* TypeTag ==> Manifest
*/
object Manifest_ClassTag {
def main(args: Array[String]) {
/**
* Q: 可以创建泛型数组吗? 理论上是不可以的,因为没有指定具体的,在Scala程序运行中,数组必须有具体的类型,没有否无法创建的相应的数组
*
* 引出Manifest的概念可以创建泛型数组
* [T : Manifest]这样的写法被称之为Manifest上下文界定 实质上这是需要一个Manifest[T]类型的隐式对象 这又是一个"隐式转换"的过程
* 通过这个隐式的值来辅助构建泛型数组,来确定T的具体类型
* 所以在创建泛型函数时 需要Manifest的类型来辅助构建泛型数组,借助Manifest类型对象来指定泛型数组具体的类型
*
* 通过Manifest[T]可以记录T的类型 在实际运行的时候我们获取T具体的类型
**/
def arrayMake[T: Manifest](first: T, second: T) = {
val r = new Array[T](2)
r(0) = first
r(1) = second
r
}
arrayMake(1, 2).foreach(println)
/**
* [T : ClassTag]这种写法说明 当这个函数在运行时 对存在一个ClassTag[T]一个隐式值 这种方式是最常用的
*/
def mkArray[T: ClassTag](elems: T*) = Array[T](elems: _*)
mkArray(42, 13).foreach(println)
mkArray("Japan", "Brazil", "Germany").foreach(println)
/**
* Manifest的原生写法,不推荐
*/
def manif[T](x: List[T])(implicit m: Manifest[T]) = {
if (m <:< manifest[String]) //<:< 表示m是manifest[String]类型
println("List strings")
else
println("Some other type")
}
manif(List("Spark", "Hadoop"))
manif(List(1, 2))
manif(List("Scala", 3))
val m = manifest[A[String]]
println(m)
val cm = classManifest[A[String]]
println(cm)
}
}
第47讲:Scala多重界定代码实战及其在Spark中的应用源码解析
class M_A[T]
class M_B[T]
/**
* scala多重界定代码实战及其在Spark中的应用源码解析
*
* T<:A with B
* T是A或者B的子类
*
* T>:A with B
* A或者B是T的子类
*
* T>:A <:B (写法上 下界必须在前边 上届必须在后面)
* T同时拥有下界A和上界B(A必须为B的子类型) 但是T不能同时拥有多个上界或者多个下界
*
* T:A:B(上下文界定)
*
* T <% A <% B(视图界定) T必须能够同时转化为A和B的要求
* T可以< 同时>拥有多个视图界定
* T可以通过"隐式转换"为A 也可以"隐式转换"为B
*
*/
object Multiple_Bounds {
def main(args: Array[String]) {
implicit val a = new M_A[Int]
implicit val b = new M_B[Int]
def foo[ T : M_A : M_B ](i:T) = println("OK")
foo(2)
}
}
第48讲:Scala类型约束代码实战及其在Spark中的应用源码解析
/**
* Scala类型约束代码实战及其在Spark中的应用源码解析
*
* A =:= B 表示A类型等同于B类型
* A <:< B 表示A类型是B类型的子类型
*/
object Type_Contraints {
def main(args: Array[String]){
def rocky[T](i:T)(implicit ev: T <:< java.io.Serializable) {
print("Life is short,you need spark!") }
rocky("Spark")
}
}
第49讲:Scala中Variance代码实战及其在Spark中的应用源码解析
/**
* Scala中Variance代码实战及其在Spark中的应用源码解析
*
* 通俗讲
* B是A的子类 ==>List[B]是List[A]的子类(与具体元素的继承关系同向) 这样称之为"协变"
* B是A的子类 ==>List[A]是List[B]的子类(与具体元素的继承关系反向) 这样称之为"逆变"
* 如果支持上面的这种概念 就被称之为"Variance" 否则称之为"inVariance"
*
* 事实上Java不支持在定义一个类型时声明为这样的"Variance"
* e.g. String是object的子类,List<String> 却不是 List<Object>的子类
* 但是Java中是存在这样的痕迹的 比如:
* List<? extends Object> list = new ArrayList<String>()
* 在Scala中也是可以向上面这样写的:
* val list: List[_ <: Any] = List[String]("Spark", "Hadoop")
*
* 事实上Java支持在使用的时候 可以这样去定义,在声明的时候不支持,但是Scala中的可以
*
* Scala中 在声明时留意表达这种Variance的关系
* 形如class C[+T] “+”表示"协变" 也就是说若B为A的子类型 则C[B]是C[A]的子类型
* class C[-T] “-”表示"协变" 也就是说若B为A的子类型 则C[A]是C[B]的子类型
*
*/
class Person
class Student extends Person
class C[+T](val args: T)
class S[+T](arg : T) extends C[T](arg)
trait Friend[-T]{
def makeFriend(somebody: T)
}
object Variance {
def makeFriendWithYou(s: Student, f: Friend[Student]){f.makeFriend(s)}
def main(args: Array[String]) {
val value : C[Person] = new C[Student](new Student)
// List<? extends Oject> list = new ArrayList<String>()
val list : List[_ <: Any] = List[String]("Spark")
}
}
第50讲:Scala中Variance变化点及其在Spark中的应用源码解析
package com.wanji.scala.type_parameterization
//class P[+T](val first: T, val second: T)
class P[+T](val first: T, val second: T){
// def replaceFirst(newFirst: T) = new P[T](newFirst, second)
//方法是泛型的 方法的参数是逆变点 返回值是协变的协变点
def replaceFirst[R >: T](newFirst: R) = new P[R](newFirst, second)
}
object Variant_Positions {
def main(args: Array[String]) {
}
}
第51讲:Scala中链式调用风格的实现代码实战及其在Spark编程中的广泛运用
package com.wanji.scala.type_parameterization
class Animal { def breathe:this.type=this }
class Cat extends Animal { def eat :this.type= this }
object Singleton_Types {
def main(args: Array[String]): Unit = {
/* * 代码2 报错
* * cat.breathe 返回的是Animal的this Animal实例没有eat方法 所以报错
* */
/*
* * 为了到达链式调用 采用代码1
* * 注意:this.type = this *
* * Q:type是指什么?
* * A:在Scala中 任何类对象都有一个type属性
* * 当执行cat.breathe其实返回的Cat类实例的type 而这个type有eat方法
* */
val cat = new Cat
cat.breathe.eat
}
}
第52讲:Scala中路径依赖代码实战详解
val outer = new Outer
val inner = new outer.Inner
/**
* Scala中的内部类 必须依赖于外部类的实例 而外部类的实例各不相同
* 所以被之为这种对于外部类的依赖为"路径依赖"
* 所以不同的路径代表不同的类型
*/
val inner2: outer.Inner = new outer.Inner
println(inner)
println(inner2)
val o1 = new Outer
val o2 = new Outer
//报错 o1与o2不是同样的实例
//val i2: o2.Inner = new o1.Inner
val i: Outer#Inner = new o1.Inner
//o1.Inner是Outer#Inner的子类。外部类#内部类:类型投影(不同外部类实例,但内部类是同一类型)。
//虽有路径依赖,但还想用Java风格就用这种表达方式。
例如:
有2个社交网络,facebook和twitter,有很多会员,是依赖于各自网络的。
就算是同一个人在这两个不同的社交网络里,也是不同的实例。
spark编程中,数据是分布式的,会分成很多的片,不同分片的数据从理论上讲是一样的(当然数据内容不同),也就是说,属于同样类型的数据,但是我们写代码时,处理数据时,还是处理属于每一个blog或split分片的结果。从这个角度看,也可看作是路径依赖。
第53讲:Scala中结构类型实战详解
/**
* Scala中结构类型实战详解
* 结构类型不关心传入的类型 只关心传入的对象具有某种行为
*/
class Structural {
def open()=print("A class instance Opened")
}
object Structural__Type {
def main(args: Array[String]){
init(new { def open()=println("Opened") })
/**
* type的作用是把“=”右边的内容起个别名
*/
type X = { def open():Unit }
def init(res:X) = res.open
init(new { def open()=println("Opened again") })
/**
* 定义单例对象
*/
object A {
def open() {println("A single object Opened")}
}
init(A)
val structural = new Structural
init(structural)
}
/**
* 从函数的定义来看,并不关心传入的对象为何,只关心传入的对象必须具有open方法
*
*/
def init( res: {def open():Unit} ) {
res.open
}
}
第54讲:Scala中复合类型实战详解
trait Compound_Type1;
trait Compound_Type2;
class Compound_Type extends Compound_Type1 with Compound_Type2
object Compound_Type {
def compound_Type(x: Compound_Type1 with Compound_Type2) = {
println("Compound Type in global method")
}
def main(args: Array[String]) {
compound_Type(new Compound_Type1 with Compound_Type2)
object compound_Type_oject extends Compound_Type1 with Compound_Type2
compound_Type(compound_Type_oject)
type compound_Type_Alias = Compound_Type1 with Compound_Type2
def compound_Type_Local(x:compound_Type_Alias) = println("Compound Type in local method")
val compound_Type_Class = new Compound_Type
compound_Type_Local(compound_Type_Class)
type Scala = Compound_Type1 with Compound_Type2 { def init():Unit }
}
}
第55讲:Scala中Infix Type实战详解
def main(args: Array[String]) {
object Log { def >>:(data:String):Log.type = { println(data); Log } }
"Hadoop" >>: "Spark" >>: Log
val list = List()
val newList = "A" :: "B" :: list
println(newList)
class Infix_Type[A,B]
val infix: Int Infix_Type String = null
val infix1: Infix_Type[Int, String] = null
case class Cons(first:String,second:String)
val case_class = Cons("one", "two")
case_class match { case "one" Cons "two" => println("Spark!!!") } //unapply
}
第56讲:Scala中Self Types实战详解
/**
* Scala中Self Types实战详解
*/
class Self {
self => //用法一:self => 表示this的别名 这是self和this等价 注意不能使用this作为别名
val tmp="Scala"
def foo = self.tmp + this.tmp
}
trait S1
class S2 {
/**
* 用法二:
* 这种方式和self =>并不一样 将S1比如为摸个trait是
* 这种this:S1为this的别名时 有一个强制的要求
* (1)在该类型实例化时 必须混入这个类型 即: val c = new S2 with S1 否则报错
* (2)在继承该类的子类是 也必须混入 比如:class S3 extends S2 with S1 若不混入with S1则报错
* */
this:S1 =>
}
class S3 extends S2 with S1
trait T { this:S1 => }
object S4 extends T with S1
object Self_Types {
def main(args: Array[String]) {
class Outer { outer =>
val v1 = "Spark"
class Inner {
/**
* 用法三:
* 这里内部类需要访问外部类成员和方法
* 通过定义了outer =>代替了外部类Outer的this
* 在内部类理由直接引用不需要考虑this是谁this
* 这是使用这种方式声明的好处
* 如果写成println(this.v1)则报错 因为这个this代表了Inner的this
* 下面的三种写法都是正确的 */
println(outer.v1)
println(v1)
println(Outer.this.v1)
}
}
val c = new S2 with S1
}
}
第57讲:Scala中Dependency Injection实战详解
trait Logger {
def log (msg : String) }
trait Auth {
auth : Logger =>
def act(msg : String) {
log(msg)
}
}
object DI extends Auth with Logger {
override def log(msg : String) = println(msg); }
object Dependency_Injection {
def main(args: Array[String]) {
DI.act("I hope you'll like it")
}
}
第58讲:Scala中Abstract Types实战详解
import scala.io.Source
import scala.io.BufferedSource
trait Reader{
/**
* 用type关键字 声明一个In类型(称为"抽象类型")
* 但是没有指明具体类型是什么类型 需要在它的实现类中指明具体的类型
* 在声明抽象类型时 可以对类型进行限定
*/
type In <: java.io.Serializable
type Contents
/**
*在抽象对的可以使用抽象类型
*/
def read(in: In): Contents
}
class FileReader extends Reader {
type In = String //实现中具体的类型
type Contents = BufferedSource //type Contents=Contents
override def read(name: In) = Source.fromFile(name)
}
object Abstract_Types {
def main(args: Array[String]) {
val fileReader = new FileReader
val content = fileReader.read("F:\1.txt")
for (line <- content.getLines){
println(line)
}
}
}
第59讲:Scala中隐式转换初体验实战详解以及隐式转换在Spark中的应用源码解析
import scala.io.Source
import java.io.File
/**
* Scala中隐式转换初体验实战详解以及隐式转换在Spark中的应用源码解析
*/
//这里的RichFile相当于File的增强类 需要的将要增强的类作为参数传入构造器中
class RichFile(val file:File){
def read = Source.fromFile(file.getPath()).mkString
}
object Context{
//File --> RichFile
//implicit是隐式转换的关键字 这里定义一个隐式转换函数把当前类型转换成增强的类型
implicit def file2RichFile(file:File)= new RichFile(file) //File -> RichFile
}
object Hello_Implicit_Conversions {
def main(args: Array[String]) {
import Context.file2RichFile
//File类本身没有read方法 通过隐式转换完成
//这里的read方法是RichFile类中的方法 需要通过隐式转换File --> RichFile
println(new File("F:\1.txt").read)
}
}
第60讲:Scala中隐式参数实战详解以及隐式参数在Spark中的应用源码解析
/**
* Scala中隐式参数实战详解以及隐式参数在Spark中的应用源码解析
*/
object Context_Implicits{
implicit val default:String = "Flink"
}
object Param{
def print(content:String)(implicit language:String){
println(language+":"+content)
}
}
object Implicit_Parameters {
def main(args: Array[String]) {
Param.print("Spark")("Scala")
import Context_Implicits._
//隐式参数没有传值,编译器会在全局范围内搜索 有没有implicit String类型的隐式值 并传入
Param.print("Hadoop")
}
}