关闭

scala学习笔记1-泛型、界定、形变、this.type、复合类型、抽象类型

标签: scala
1845人阅读 评论(0) 收藏 举报
分类:

一、Scala中的泛型
class Triple[F: ClassTag, S : ClassTag, T : ClassTag](val f : F, val s : S, val t :T)  <span style="font-family: Arial, Helvetica, sans-serif;">//其中,ClassTag在scala.reflect.ClassTag中,并且ClassTag是隐式的,可省略;</span>
val t1 = new Triple("hadoop", "spark", "bigdata");
val t2 = new Triple[String, Int, Double]("bigdata", 1, 1.0);


二、Scala中Bounds(界定)

    一般的Bounds

    <: 使得T必须是Comparable[T]的子类,这T类型的a,b才有compareTo方法。

class Pair[T <: Comparable[T]](val a : T, val b : T)
if(a.compareTo(b)> 0) a else b

    View Bounds(视图界定)

class Pair2 [T <% Comparable[T]](val a : T, val b :T)
<% 使得T不是Comparable[T]的子类型,隐式转为它的子类。比如传入的是Int类型,Int类型没有实现Comparable[T]。故先要将Int隐式转为RichInt,此时RichInt是Comparable[T]的子类
class Pair3 [T <% Ordered[T]](val a : T, val b : T)
转为Ordered[T],可以将对象以a > b 的形式进行比较。If(a>b) a else b,其实>是a的方法

    Context Bounds

class Pair_Ordering [T : Ordering : ClassTag](val a : T, val b : T) {
     def bigger(implicit ordered : Ordering[T]) ={
         if(ordered.compare(a, b) > 0) a else b
      }
}
T :Ordering表示存在一个隐式值为Ordering[T]

     Manifest、classManifest、ClassTag、TypeTag

      利用Manifest可以创建泛型数组。Manifest中存储了T的实际类型的信息,在实际运行中作为参数运行在上下文环境中。其中T:Manifest和上文的T:Ordering都属于Context Bounds的用法

def arrayMake[T : Manifest](a : T, b : T) = {
    val array = new Array[T](2);
    array(0) = a;
    array(1) = b;
    array;
}

         后来,Manifest和classManifest分别被TypeTag和ClassTag所取代。ClassType的限定要弱于TypeTag。ClassType提供了运行时的类型信息,而TypeTag提供了所有的静态类型信息。而实际中,ClassType提供的运行时类型信息已经足够使用,因此在spark等中使用广泛。

           def arrayMake2[T : ClassTag](elems : T*) = Array[T](elems : _*)

            ,这里可以看到T:ClassTag,自动隐式转为ClassTag[T]

            arrayMake2(1,2).foreach(println)

           主要是在运行时指定在编译时无法确定的比较高级别的类别的信息,不包括static级别的type信息。

    多重界定

          T <:A with B 表示T是AB的子类。

          T : A: B 是上下文界定。表示必须同时存在A[T]和B[T]的隐式值。

          T <% A <% B 是视图界定,表示T可以隐式转为AB。

          T>: A <: B 表示A是T的下界,B是T的上界。并且,下界A必须写在上界B的前面,同时A一定是B的子类。

三、 Scala的类型约束

     A =:=B 表示A类型等同B类型

     A<:< B 表示A类型是B类的子类型

四、 Scala中的Variance

    Variance称为形变 T

       协变 +T

       逆变 –T

       class  Person[+T](first : T, second : T) 则后面的first和second的类型必须是T的父类。-T的话,表示first和second的类型必须是T的子类。

五、 Scala中的链式调用

     任何的类对象都有type属性:this.type

class Animal {
  def breathe() : this.type = {
      //TODO
      this
  }
}
    
class Dog extends Animal {
 def eat() : this.type = {
    //TODO
    this
  }
}
Val dog = new Dog; dog.breathe().eat();

六、 Scala中的路径依赖

    内部类享有外部类的实例,可以访问外面类中的私有成员;而外部类不可以访问内部类中的私有成员。

    Scala中内部类必须依赖于外部类的实例。外部类实例不同,则内部类也不同,依赖于外部类,称为路径依赖,不同路径下的内部类,类型不同。

class Outter {
   private[this] val x = 1
     
   class Inner {
      private[this] val y = x + 1
    }
}
 
object PathDependencies extends App {
  val out1 = new Outter
  val out2 = new Outter
 
  //out1.Inner和out2.Inner在不同路径下,类型不同
  val inner1 : out1.Inner = new out1.Inner
  val inner2 : out2.Inner = new out2.Inner
 
  //类型投影,out1.Inner,out2.Inner是Outter#Inner的子类
  val inner3 : Outter#Inner = new out1.Inner
  val inner4 : Outter#Inner = new out2.Inner
}

七、 Scala中的结构体类型

//传入实现get方法的匿名类实例
init(new {def get() = println("geted")})
       
//申明一个含有get方法的类型,类型于c语言中的结构体类型
type X = {//不需要像java那样,通过接口和实现接口来限制
   def get() : Unit
}
def init1(res : X) = {
   res.get
}
init1(new {def get() = println("geted again")})
object A {def get() = println("geted In A")}
init1(A)

八、 Scala中的复合类型

trait A //接口A
trait B //接口B
class C extends A with B {//继承A,B,实现get的C
   def get() = println("hello compoundtype!")
}
   
object CompoundType {
    //复合类型,该类型表示既是A又是B,同时还要实现get方法
    type CompoundType = A with B {def get():Unit}
 
    def init(x : CompoundType)  = {
       x.get()
    }

    def main(args: Array[String]): Unit = {
      init(new C)
    }
}

九、 Scala中的InfixType

object InfixType {
   def main(args: Array[String]): Unit = {
       //右结合的表达式
      "Spark" >>: "Hadoop">>: Log
       
       val list = List()
       val newList = 1 :: 2 :: list
       println(newList)
       
       class Infix_Type[A, B]
       val it : Infix_Type[Int, String] =null
       val it1 : Int Infix_Type String =null
   
       val cons =Constant("1", "2")
       cons match {
         case "1" Constant "2"=> {
          println("spark!")
         } 
       }
   }
}
case class Constant(first : String, second : String)
 object Log {
   def >>: (data : String) : Log.type = { // >>: 这是方法名
     println(data);
     Log
  }
}


十、Self Types

      自类型, 相当于对当前实例关键this起一个别名。用法如下://有点类似于javascript中的var self = this; 的用法

Class Outter {
   self =>
   val i
   Class Inner {
      def foo(){ println(self.i) }
   }
}

      主要用途在对this的一种限定,必须要混入另一个类型。用法如下:

trait S1
class S2 {
     this:S1=>
}
val s = new S2 with S1  //实例化S2的时候需要with S1
class S3 extends S2 with S1  //extends S2的时候需要 with S1

十一、 Scala中的依赖注入

      通过self type的用法,实现依赖组件的注入

object DependenceInjection extends App {
   T.authorize()
}
trait Logger{
   def log(msg:String)
}
class Auth{
   auth : Logger => //关键点
   val key = "hello di"
   def authorize() = {
     log(key)
      //TODO
   }
}

//T对象继承Auth则必须with Logger实现log方法
object T extends Auth with Logger {
   override def log(msg:String) = {
     println(msg)
   }
}

十二、 Scala中的抽象类型AbstractType

     抽象类通过type声明类型,但不指定具体的类型

     在子类中指定相关类型,和实现抽象类中的方法

trait Reader {
     type input <: java.io.Serializable //input 必须是Serializable的子类
     type results
     def read(str : input) : results
}              

class FileReader extends Reader {
    type input = String
    type results = BufferedSource
    override def read(str : input):results = {
        Source.fromFile(str)
    }
}

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:21675次
    • 积分:338
    • 等级:
    • 排名:千里之外
    • 原创:12篇
    • 转载:4篇
    • 译文:0篇
    • 评论:0条
    文章分类
    友情链接