前传第15课:Scala类型参数编程实战及Spark源码鉴赏
本課課程:
- Spark源码中的Scala类型系統的使用
- Scala类型系統编程操作实战
Spark源码中的Scala类型系統的使用
classOf[RDD[_]] 這個也是类型系統
這里的意思是說 B 這種類型必需至少是 A 這樣類型
Ordering
Scala类型系統编程操作实战
作為類型系統最大的就可以對類型進行限制,在Scala 中的類型系統,他本身也作為對象。e.g. 我們可以建立 Person 這個類,現在可以建立一個什麼類型的 Person,比如說億萬富翁這種類型的人
- Scala 的類和方法、函数都可以是泛型,在 Spark 源碼中到處都可以看到類和方法的泛型,在實際實例化的時候指定具體的類型,例如Spark 最核心、最基礎、最重要的描象數據結構裡面關於 RDD 的類的定義是泛型,RDD 的几乎所有方法的定義也都是泛型的,之所以這麼做是因為 RDD 會派生很多子類,通過子類配了各種不同的數據源以及業務邏輯操作。
- 關於對類型邊界的限定,分為上邊界和下邊界:
- 上邊界 UpperBound:表達了泛型的類型必需是某種類型的或者某種類型的子類,語法為 <:這里的一個新的現象是對類型進行限定;(自己或者是小於你自己) < identifier : upper bound - the highest acceptable class type >
“A is less than B ... A is under B ... A is a subtype of B.” - 下邊界 LowerBound:表達了泛型的類型必需是某種類型的或者某種類型的父類,語法為 >:這里的一個新的現象是對類型進行限定;(自己或者是大於你自己) < identifier : lower bound - the lowest acceptable class type >
這個例子表明:The highest acceptable class type 是 Person,所以要求傳入的參數一定是 Person 或者是 Person 的子類 (即 Worker)
如果傳進來的不是 Person類或者是 Worker 類,會編譯有錯
- 上邊界 UpperBound:表達了泛型的類型必需是某種類型的或者某種類型的子類,語法為 <:這里的一個新的現象是對類型進行限定;(自己或者是小於你自己) < identifier : upper bound - the highest acceptable class type >
- View Bounds,可以進行某種神祕的轉換,把你的類型可以在沒有知覺的情況下轉換成目標類型,其實你可以認為 View Bounds 是上邊界和下邊界的加強補充版本,例如在 SparkContext 這個 Spark 的核心類中有 T <% Writable 方式的代碼,這個代碼所表達的是 T 必需是 Writable 類型的 (the highest acceptable class type is Writable),但是 T 又沒有自己继承至 Writable 接口,此時就需要通過 “implicit” 的方式來實現這個功能。
第一點:寫出 Person, Worker and Dog 之間的继承結構,Worker 是继承 Person (Person 是父類、Worker 是子類),Dog 跟 Person 沒有任何關係;
第二點:判断 class Cub 的 Type Variance 是什麼,在這個例子是 [ T <% Person ],意思是接受所有继承著 Person 的子類或者 Person 本身,也就是說在這例子中接受 Person 或者是 Person 的子類, 即 Worker;
第三點:检查参数的正确性,如果T本身是Person,那就是可以传入Person和Worker;如果T本身是Worker,那就是只可以传入Worker,但需求是要傅入 Dog 類 ,因為這個是 View Bound 所以可以用隐式转换 Implicit,Dog 因為跟 Person 沒有任何關係,它會找關鍵字 Implicit 來判斷自己是否可以轉換成 Person 類! implicit def dog2Person(dog: Dog) = new Person(dog.name),找到了它會自動轉換成 Person 類然後傅入 communicate 這個方法里!隐式转换成功!
- T: ClassTag,例如 Spark 源碼中的 RDD class RDD[T: ClassTag] 這個其實也是一種類型轉換系統,只是在編譯的時候類型信息不夠,需要借助 JVM 的 runtime 來通過運行時信息來獲得完整的類型信息,這在 Spark 中是非常重要的,因為 Spark 的程序的編寫和運行是區分了 Driver 和 Executor 的,只有在運行的時候才知道完整的類型信息。
- 协变与逆变:[-T] 和 [+T] e.g. Expert 是Engineer 的子類,所以逆变 covariant 是自己/ 自己以下的子類;逆变 contravariant 是自己/ 自己以上的父類。
以下是协变的例子:
第一點:寫出 Engineer 跟 Expert 之間的继承結構,Expert 是继承 Engineer (Engineer 是父類、Expert 是子類);
第二點:判断 class Meeting 的 Type Variance 是什麼,在這個例子是 [+T],意思是接受所有继承著 T 的子類或者 T 本身,也就是說在這例子中接受 Engineer 或者是 Engineer 的子類, 即 Expert;
第三點:判断方法需要传入的类型是什么,在这例子要求传入的是 Meeting[Engineer];
第四點:检查参数的正确性,如果T本身是Engineer,那就是可以传入Engineer和Expert;如果T本身是Expert,那就是只可以传入Expert,如果有此時传入 Engineer,会编译错误!以下是逆变的例子:
第一點:寫出 Engineer 跟 Expert 之間的继承結構,Expert 是继承 Engineer (Engineer 是父類、Expert 是子類);
第二點:判断 class Meeting 的 Type Variance 是什麼,在這個例子是逆变 [-T],意思是接受所有 T 本身或者是 T 的父類,也就是說在這例子中只接受 Engineer ;
第三點:判断方法需要传入的类型是什么,在这例子要求传入的是 Meeting[Engineer];
第四點:检查参数的正确性, 如果 T 本身是 Expert, 那就是可以传入Engineer和Expert;如果 T 本身是 Engineer, 那就是只可以传入 Engineer;如果有此時传入 Expert,会编译错误!
- Context Bound,T: Ordering 这种语法必顺能够编程 Ordering[T] 这种方式。
Reference: Programming Scala Chapter 10
Suppose a method takes an arguments of type List[AnyRef], can you pass a List[String] value (Should a List[String] be considered as a subtype List[AnyRef]. If true, this kind of variance is called covariance. We can also have types that are contravariant, where X[String] is a super-type of X[Any].
For covariance type parameters, + is used
For contravariant type parameters, - is used
covariance
invariance
contravariant
[+A]:自己/自己的子類
[A]:自己
[-A]:自己/自己的父類
What is the difference between Type Variance, View Bound and Context Bound?
Why we need to apply the Type System in Programming? What are the pros and cons?