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

标签: scala
2136人阅读 评论(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)
    }
}

查看评论

Scala入门之高级类型:this.type

this.type在写Spark程序的代码中一开始就能看到这代码: val conf = new SparkConf conf.setAppName("OnlineBlackListF...
  • pofengliuming
  • pofengliuming
  • 2016-08-09 15:24:10
  • 1693

scala中的this.type

自从开始看scala的Parser相关的源码以来,我越来越觉得scala中很多处理方法就像是用黑魔法在与编译器打交道。不变成JVM上的c++誓不罢休? 看Programming in Scala...
  • javastart
  • javastart
  • 2016-02-11 16:48:23
  • 1441

scala的协变和逆变分析

首先引用朋友的文章 http://freewind.me/blog/20140502/2613.html d
  • daaoke
  • daaoke
  • 2014-05-02 21:09:48
  • 4100

Scala教程(十四)Scala泛型及约束实战

ClassTag[T]保存了泛型擦除后的原始类型T,提供给被运行时的。 泛型参数类型限定:限定具体类的可以调用特定的方法。 泛型视图限定:表示把传入不是Comparable[T]类型的 隐式传换 为C...
  • yuan_xw
  • yuan_xw
  • 2015-10-23 17:33:32
  • 8666

Scala入门到精通——第十六节 泛型与注解

本节主要内容 泛型(Generic Type)简介 注解(Annotation)简介 注解常用场景 1. 泛型(Generic Type)简介泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时...
  • lovehuangjiaju
  • lovehuangjiaju
  • 2015-08-04 20:23:21
  • 13450

scala基础之泛型详解

在Scala中你可以使用类型参数来实现类和函数,这样的类和函数可以用于多种类型。比如Array[T] 你可以存放任意指定类型T的数据. 类、特质、函数都可以有类型参数;将类型参数放在名字后面用方括号...
  • zhanglh046
  • zhanglh046
  • 2017-06-02 16:54:52
  • 1734

Scala学习——泛型[T]的6种使用

package com.dtspark.scala.basics/** * 1,scala的类和方法、函数都可以是泛型。 * * 2,关于对类型边界的限定分为上边界和下边界(对类进行限制) *...
  • fz2543122681
  • fz2543122681
  • 2017-02-21 17:32:17
  • 1490

第42讲:Scala中泛型类、泛型函数、泛型在Spark中的广泛应用学习笔记

第42讲:Scala中泛型类、泛型函数、泛型在Spark中的广泛应用   第42讲是进阶阶段第一讲 1-41是入门经典,学习了scala的基本类型,面向对象编程,函数式编程和 集合的操作,模式...
  • slq1023
  • slq1023
  • 2015-08-05 22:38:30
  • 2677

scala 泛型之初解,定界,类型约束,逆变与协变

scala 的泛型应用如下: 一、初解 当构建一个类或者函数时,如果我们不知道(或者说不确定)传入的参数的具体数据类型,这时候可以泛型,例子如下: 1-1例子: object test0 extend...
  • u010666884
  • u010666884
  • 2016-07-27 10:58:02
  • 1352

scala泛型操作

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。scala也采用了Java的泛型擦除模式(erasure),即类型是编译期的,在运行时会被"擦除"的,即运行时看不到类型参数。 ...
  • u013063153
  • u013063153
  • 2016-12-19 23:16:56
  • 844
    个人资料
    等级:
    访问量: 2万+
    积分: 382
    排名: 20万+
    友情链接