Scala零基础教学【41-60】

 

第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")
  }
}

  

posted @ 2018-09-20 16:09  Mars、少年  阅读(187)  评论(0编辑  收藏  举报