Scala教程(十六)Scala复合类型与依赖注入详解


 

 

Scala教程(十六)Scala复合类型与依赖注入详解

 


1 Scala类型与依赖注入


1.1 函数链式调用

   Scala中任务对象都有type属性,cat对象调eat方法时,this指向当前调用对象。

    class Animal { def breathe : this.type = this }
    class Cat extends Animal { def eat(){println("=====eat=====")}}
    
    object SingletonTypes {
        def main(args: Array[String]): Unit = {
            val cat = new Cat();
            // 执行结果:=====eat=====
            cat.breathe.eat();
        }
    }<span lang="EN-US" style="font-family:Consolas;color:black;font-size:12.0pt;"> 
</span>

1.2 路径依赖

Scala的内部类比Java的内部类具有更多特性,因此Scala引入了路径依赖类型(Path-dependent type)的概念。像outer.Inner这样的类型就称为路径依赖类型。所谓路径,指的就是参考外部类所建立的实例的名称。 outer.Inner这个类型来说,路径为outer。更重要的是,不同路径代表不同的类型。

    val o1 = new Outer;
    val o2 = new Outer;
    val i1 =  new o1.Inner;
    val i2 =  new o2.Inner;
    
    // o1.Inner类属于Outer#Inner的子类,这方式称之为类型投影
    val i: Outer#Inner = new o1.Inner
 

尽管o2o1引用同一个实例,但o1.Innero2.Inner是不同的,Scala编译器只根据路径名进行区分:

    val o1 = new Outer
    val o2 = o1
    val i1: o1.Inner = new o1.Inner
    val i2: o2.Inner = new o1.Inner // 编译错误。

1.3 结构类型

结构类型又称之为鸭子类型,即:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。

    // 伴生类
    class StructuralType{
        // 定义函数
        def open() = println("A class instance Opened");
    }
    object StructuralType {
      def main(args: Array[String]): Unit = {
      
        // new {} 对象,对象中存在 open方法,即可调用open。执行结果:Opende
        init(new {def open() = println("Opende")});
        
        // type:即把 = 后面的内容命名为别名
        type x = {def open():Unit}
        
        object A {def open() {println("A single object Opened")}}
        // 执行结果:A single object Opened
        init(A);
        
        // structural 实例中包含open方法,即可调用open。执行结果:A class instance Opened
        val structural = new StructuralType();
        init(structural);
      }
      
      
      	// 结构类型又称之为鸭子类型,即:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。
        // 定义init函数,参数具有open方法的对象 
        def init(res:{def open():Unit}){
            res.open();
        }
        /*
         *  不过Scala编译成Reflection实现:Why scala uses reflection to call method on structural type?
         *  文章中说性能差事反射的性能问题,随着JVM引入invokedynamic  指令,会有很大的性能提升,但是这只在JVM1.7才有,
         *  但是scala2.11还支持JVM1.6, 所以最好还是不要大量使用,当然目前貌似也没有太多使用的。
         *  
         *  Reflection参考文章:
         *  1. http://en.wikibooks.org/wiki/Scala/Structural_Typing
         *  2. http://java.dzone.com/articles/duck-typing-scala-structural
    	 *  3. http://www.draconianoverlord.com/2011/10/04/why-no-one-uses-scala-structural-typing.html
    	 *  4. http://stackoverflow.com/questions/8539422/why-scala-uses-reflection-to-call-method-on-structural-type 
         */
    }

1.4 复合类型

T1with T2 with T3 …,这种形式的类型称为复合类型(compoundtype)或者也叫交集类型(intersection type)

    // 定义特征(CompoundType1、CompoundType2)
    trait CompoundType1;
    trait CompoundType2;
    
    class CompoundType extends CompoundType1 with CompoundType2;
    
    object CompoundType {
        // 定义方法compoundType,该方法需要传递即参数满足CompoundType1类型且又要满CompoundType2类型的,复合类型。
        def compoundType(x:CompoundType1 with CompoundType2) = {println("Compound Type in global method!!!")}  
        
        def main(args: Array[String]): Unit = {
            // new出即符合CompoundType1类切也符合CompoundType2类型,执行结果:Compound Type in global method!!! 
            compoundType(new CompoundType1 with CompoundType2)
            
            // object 混入代码中,将object对象当参数传递方法,执行结果:Compound Type in global method!!!
            object compoundTypeObject extends CompoundType1 with CompoundType2
            compoundType(compoundTypeObject);
            
            // 使用type关键字,起别名 
            type compoundTypeAlias = CompoundType1 with CompoundType2;
            // 定义函数,参数使用别名compoundTypeAlias类型
            def compoundTypeLocal(x:compoundTypeAlias) = println("Compound Type in local method!!!");
            // 别名的函数调用,执行结果:Compound Type in local method!!!
            var compoundTypeClass = new CompoundType();
            compoundTypeLocal(compoundTypeClass);
            
            // 定义复合类型:在CompoundType1并且CompoundType2类,同时必须实现在init方法。
            type Scala = CompoundType1 with CompoundType2 {def init():Unit}
        }
    }

1.5 scala中缀表达

scala中的中缀表达在3个地方存在:操作符、模式匹配、类型声明。中缀操作符最常见: a +b x foo y 里的+foo都是中缀操作符(严格的说scala里没有操作符,其实都是方法)。

    object InfixType {
      def main(args: Array[String]): Unit = {
        // >>:操作符是函数名,定义def。 把数据追加到log中,执行结果:Scala Spark Hadoop 
        object Log { def >>:(data: String): Log.type = { print(data + " "); Log } }
        "Hadoop" >>: "Spark" >>: "Scala" >>: Log
    
        // 最常见的从右往左结合的中缀操作符是 List 的 :: 方法
        val list = List();
        val newList = "A" :: "B" :: list;
        // 执行结果: List(A, B)
        println(newList);
    
        // 中缀类型:泛型带有两个带参数的类型A,B。
        // 语法:类型 ClassName 类型:即 Int InfixType String 等同于 InfixType[Int,String]
        class InfixType[A, B]
        val infix: Int InfixType String = null;
    
        // 模式匹配:中缀表达
        case class Cons(first: String, second: String)
        val case_class = Cons("one", "two");
        case_class match {
          // 即 "one" Cons "two" 等同于 Cons("one", "two")
          case "one" Cons "two" => println("Spark!!!");
        }
      }
    }

1.6 scala自身类型

    /*
     * self不是关键字,可以用除了this外的任何名字命名(除关键字)。
     * this代表当前对象,this和self是等价的。
     */
    class Self {
      self => // this别名
      val tmp = "Scala";
      def foo = self.tmp + this.tmp
    }
    
    trait S1
    // S2在实例化时或定义S2的子类时,必须混入指定的S1类型(也可以为当前类型,如:class S2 {this:S2 => })
    class S2 { this: S1 => }
    class S3 extends S2 with S1
    // class S4 { this => } //error 不能用this做别名
    
    object SelfType {
      def main(args: Array[String]): Unit = {
    
        /*
         * 内部类 
         */
        class Outer {
          outer => // Outer类的this别名outer
          val v1 = "Spark";
          class Inner {
            // 用outer表示外部类,相当于Outer.this
            println(outer.v1);
          }
        }
        // 构造对象,实例化S2必须混入S1
        var c = new S2 with S1
      }
    }

1.7 scala抽象类型

    trait Reader {
      // 定义类型In,In类型的上界为java.io.Serializable
      type In <: java.io.Serializable;
      type Contents;
      // 定义read函数,参数为In类型,返回值为Contents类型
      def read(in: In): Contents;
    }
    
    /*
     * FileReader类实现Reader特征
     */
    class FileReader extends Reader {
      // 在实现类中In类型被赋值具体String类型
      type In = String;
      // Contents类型被赋值具体BufferedSource类型
      type Contents = BufferedSource;
    
      // 实现read函数
      override def read(name: String) = Source.fromFile(name);
    }
    
    object AbstractTypes {
      def main(args: Array[String]): Unit = {
        val fileReader = new FileReader();
        val file = fileReader.read("E:\\input.txt")
    
        /*
         *  执行结果:
         *  I feel Great!!!
         *  I am into Music so much!!!
         */
        for (line <- file.getLines()) { println(line); }
        // 文件关闭  
        file.close();
      }
    }


1.8 AOP依赖注入

依赖注入:是指依赖对象的创建,由第三方完成,而不是被依赖对象,我们将这种控制关系的转移,称为依赖注入或者控制反转。

    trait Logger {
      def log(msg: String)
    }
    trait Auth {
      auth: Logger => // 别名auth
      def act(msg: String) {
        // 调用被依赖的对象Logger 的log 方法
        auth.log(msg)
      }
    }
    
    object DI extends Auth with Logger {
      // 重写父类的方法
      override def log(msg: String) = println(msg);
    }
    
    object DependencyInjection {
      def main(args: Array[String]) {
        // DI为静态对象,执行结果:dependency injection
        DI.log("dependency injection")
      }
    }

 

    --以上为Scala复合类型与依赖注入详解,谢谢大家对我的关注。

                                                                                                                                                                                      ——厚积薄发(yuanxw)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值