scala别名与自身类型
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_person
和ordinary_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