美文网首页
scala别名与自身类型

scala别名与自身类型

作者: CarsonCao | 来源:发表于2019-11-13 20:39 被阅读0次

    this 别名

    看scala的源码的话很发现很多源码开头都有一句:self => 这句相当于给this起了一个别名为self

    class A { 
        self =>  //this别名
        val x=2 
        def foo = self.x + this.x 
    }
    

    self不是关键字,可以用除了this外的任何名字命名(除关键字)。就上面的代码,在A内部,可以用this指代当前对象,也可以用self指代,两者是等价的。
    self => 这种写法只是自身类型的一种特殊方式。

    自身类型(self type)

    格式:this: X =>

    trait A { 
        this: X =>
    }
    

    this:X => 要求A在实例化时或定义A的子类时,必须混入指定的X类型,这个X类型也可以指定为当前类型:
    class A { this:A => }

    自身类型的存在相当于让当前类变得“抽象”了,它假设当前对象(this)也符合指定的类型,因为自身类型 this:X =>的存在,当前类构造实例时需要同时满足X类型

    scala> new C // 不满足
    <console>:10: error: class C cannot be instantiated because it does not conform to its self-type C with X
    
    // ok, 相当于构造一个复合类型(C with X)的实例
    scala> val c = new C with X
    

    在定义C的子类时,因为自身类型的约束,也必须满足X类型,即子类必须也混入X.

    再看一个scala官网上的例子:

    trait User {
      def username: String
    }
    
    trait Tweeter {
      this: User =>  // reassign this
      def tweet(tweetText: String) = println(s"$username: $tweetText")
    }
    
    class VerifiedTweeter(val username_ : String) extends Tweeter with User {  // We mixin User because Tweeter required it
        def username = s"real $username_"
    }
    
    val realBeyonce = new VerifiedTweeter("Beyonce")
    realBeyonce.tweet("Just spilled my glass of lemonade")  // prints "real Beyonce: Just spilled my glass of lemonade"
    

    VerifiedTweeter类想要扩展特质Tweeter,必须要同时使用特质User。细心的同学发现以上的例子都发生在特质trait中。scala官方也强调自我类型必须是特质trait类型,也就说self:T=>中的T必须是trait ,如果不是trait会报class <T> needs to be trait to be mixed in.的错误。

    Self-types are a way to declare that a trait must be mixed into another trait, even though it doesn’t directly extend it. That makes the members of the dependency available without imports.
    https://docs.scala-lang.org/tour/self-types.html

    我们额外再看一些例子:

    // Scala Program that uses self type 
    trait with_powers 
    {  
        var mind ="extra-ordinary";  
          
    } 
    trait without_powers 
    { 
        var mind="ordinary"; 
    } 
    trait person 
    {  
        def brain(); 
    } 
      
    // class extend trait 
    class extraordinary_person extends person 
    {    
        // reassign this 
        this: with_powers => 
        override def brain() = println(s"super hero brain is $mind!"); 
    } 
      
    // class extend trait 
    class ordinary_person extends person 
    {    
        // reassign this 
        this: without_powers => 
        override def brain() = println(s"normal human brain is $mind."); 
    } 
      
    // Creating object 
    object GFG 
    { 
        // Main method 
        def main(args:Array[String]) 
        { 
            val hero = new extraordinary_person() with with_powers; 
            val mohan = new ordinary_person() with without_powers; 
              
            //val mohan= new ordinary_person() with with_powers; ERROR 
            //does not conform to ordinary_person's self type 
            hero.brain(); 
            mohan.brain(); 
        } 
    } 
    
    // Output:
    // super hero brain is extra-ordinary!.
    // normal human brain is ordinary.
    

    在上面的例子中,我们创建了with_powers, without_powers,和person这几个特质,extraordinary_personordinary_person两个类分别继承person,同时两个类分别声明了自身类型,在实例化两个类的时候必须要mix in自身类型的trait,如果声明错误了会报错。

    再看一个例子:

    // Scala Program that uses self type 
    trait A 
    {  
        def x = 1
    } 
      
    // trait extend another trait 
    trait B extends A 
    { 
        override def x = super.x * 5
    } 
      
    // trait extend another trait 
    trait C1 extends B 
    { 
        override def x = 2
    } 
      
    // trait extend another trait 
    trait C2 extends A 
    {  
        this: B=> 
        override def x = 2
          
    } 
      
    // Creating object 
    object GFG 
    { 
        // Main method 
        def main(args:Array[String]) 
        { 
            println((new C1 with B).x); 
            println((new C2 with B).x); 
        } 
    } 
    

    trait是不能直接new的,但是上面(new C1 with B)应该是通过with构建一个混合类型对象,然后调用混合类型对象中的x;(new C2 with B)中由于C2中有自身类型B,所以会直接调用B中的x的定义,由于C2继承自A,所以super.x实际为2,然后结果为10,有兴趣的同学可以打断点调试一下看看。

    参考:
    https://www.geeksforgeeks.org/scala-self-types-annotation/
    https://docs.scala-lang.org/tour/self-types.html
    http://hongjiang.info/scala-type-system-self-type/
    http://hongjiang.info/scala-self-type-and-di/
    https://blog.csdn.net/bluishglc/article/details/60739183

    相关文章

      网友评论

          本文标题:scala别名与自身类型

          本文链接:https://www.haomeiwen.com/subject/iygebctx.html