Scala 自身类型(self-type) 解析

Scala 有一个自身类型(self-type) 的东西,由来已久,居然今天才发现。如果一个类或 trait 指明了 self-type 类型(包括类和特质),它的子类型或是对象也必须是相应的类型。它产生的效果与继承(或 mixin) 颇有几分相似。self-type 的语法是 this 的别名: 某一类型(class 或 trait), 直接看一个例子:
 1class User(val name: String)
 2
 3trait Tweeter {
 4  this: User =>  //这个表示 Tweeter 本身也必须是一个 User,它的子类型必须想办法符合这一要求
 5  def tweet(tweetText: String) = {
 6    println(s"$name: $tweetText")
 7  }
 8}
 9
10class VerifiedTweeter(val username: String)
11  extends User(username) with Tweeter {  //Tweeter 要求这个类必须是一个 User, 所以需要继承自 User 类
12}
13
14val v = new VerifiedTweeter("Yanbin")
15v.tweet("Hello")

上面 this: User => 中的 this 只是一个别名,可以是 self 或任何有效标识(如  abc: User),这里使用 this 等于未指定别名,与原本的 this 重叠了。如果声明为非 this 的话则可以这么用
1trait Tweeter {
2  abc: User =>
3  def tweet(tweetText: String) = {
4    println(s"${this.name}-${abc.name}: $tweetText")
5  }
6}

this 永远都在,同时 abc 与 this 是完全一样的效果。


注(2018-02-14): 这个语法只是用作 this 别名的话,后面可以不用接类型,例如
1trait Tweeter {
2  abc =>
3  .... //代码中 abc 就是 this 的别名,它们是等效的
4}



如果在声明 VerifiedTweeter 类只是混入 Tweeter 特质会怎么样呢?以下两种声明都将产生同样的编译错误


如果 User 也是一个 trait,那么声明 VerifiedTweeter1 时可以同时混入 User, 即
1trait VerifiedTweeter1 extends Tweeter with User

由于前面 User 也是一个类,所以需要让 mixin Tweeter 的类继承自 User , 就是
1class VerifiedTweeter(val username: String)
2  extends User(username) with Tweeter {
3}

self-type 可以指定多重类型,那么声明子类型或创建实例时也要符合多种类型
 1trait User
 2trait Animal
 3
 4trait Tweeter {
 5  this: User with Animal =>
 6}
 7
 8class VerifiedTweeter extends Tweeter with User with Animal
 9
10//直接创建实例
11new Tweeter with User with Animal

还有一种结构类型的 self-type, 更像是匿名类型的 self-type, 不是指定类型名而是类型必须实现的方法,例如

定义中声明了
 this: {def say: Unit} =>

要求在 Tweeter 中必须实现该方法,如
 1class Tweeter extends User {
 2  def say: Unit = {
 3    println("say something")
 4  }
 5}
 6
 7//或者创建匿名的 User 类及实例
 8val user = new User {
 9  def say: Unit = {
10    println("say something")
11  } 
12}

最后,注意一下 this: User => 这个语法后不能用大括号括起后续的代码
1trait Tweeter {
2  this: User => {
3    def tweet(tweetText: String) = {
4      println(s"$name: $tweetText")
5    }
6  }
7}

以上代码编译没有问题,但创建的 Tweeter 实例是看不到 tweet(...) 方法的。

链接:
  1. TOUR OF SCALA SELF-TYPE
  2. Self Type Annotation
  3. scala类型系统:9) this别名&自身类型
永久链接 https://yanbin.blog/scala-self-type-understanding/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。