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

trait TraversableLike[+A, +Repr] extends Any
                                    with HasNewBuilder[A, Repr]
                                    with FilterMonadic[A, Repr]
                                    with TraversableOnce[A]
                                    with GenTraversableLike[A, Repr]
                                    with Parallelizable[A, ParIterable[A]]
{
  self =>

  import Traversable.breaks._

  /** The type implementing this traversable */
  protected[this] type Self = Repr

  /** The collection of type $coll underlying this `TraversableLike` object.
   *  By default this is implemented as the `TraversableLike` object itself,
   *  but this can be overridden.
   */
  def repr: Repr = this.asInstanceOf[Repr]

  final def isTraversableAgain: Boolean = true

self不是关键字,可以用除了this外的任何名字命名(除关键字)。就上面的代码,在A内部,可以用this指代当前对象,也可以用self指代,两者是等价的。

它的一个场景是用在有内部类的情况下:

class Outer { outer => 
    val v1 = "here"
    class Inner {
        println(outer.v1) // 用outer表示外部类,相当于Outer.this
    }
}

但当声明了类型的时候,就不是别名的用途了,这个时候表示自身类型,比如:

class C { this:X => }

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

scala> class C { this:C => } // 不会报错

自身类型的存在相当于让当前类变得“抽象”了,它假设当前对象(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

class D extends C with X

注意上面两种情况下X都为特质(trait)。

如果自身类型是定义在特质中(大多情况下):

trait T { this:X => }

那么当某个class或object 要继承或混入 T 时,必须也要满足 X 类型,如果该类/单例不是X的子类的话就要同时混入X才可以

object A extends T with X

最后,自身类型也可以声明为复合类型

this: X with Y with Z =>

或声明为结构类型

this: { def close:Unit} =>

另外,自身类型中,可以用this也可以用其他名字,如self。


评论