scala别名与自身类型

2019-11-13  本文已影响0人  CarsonCao

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

上一篇下一篇

猜你喜欢

热点阅读