Scala 有一个自身类型(self-type) 的东西,由来已久,居然今天才发现。如果一个类或 trait 指明了 self-type 类型(包括类和特质),它的子类型或是对象也必须是相应的类型。它产生的效果与继承(或 mixin) 颇有几分相似。self-type 的语法是 this 的别名: 某一类型(class 或 trait), 直接看一个例子:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class User(val name: String) trait Tweeter { this: User => //这个表示 Tweeter 本身也必须是一个 User,它的子类型必须想办法符合这一要求 def tweet(tweetText: String) = { println(s"$name: $tweetText") } } class VerifiedTweeter(val username: String) extends User(username) with Tweeter { //Tweeter 要求这个类必须是一个 User, 所以需要继承自 User 类 } val v = new VerifiedTweeter("Yanbin") v.tweet("Hello") |
上面 this: User => 中的 this 只是一个别名,可以是 self 或任何有效标识(如 abc: User),这里使用 this 等于未指定别名,与原本的 this 重叠了。如果声明为非 this 的话则可以这么用
|
1 2 3 4 5 6 |
trait Tweeter { abc: User => def tweet(tweetText: String) = { println(s"${this.name}-${abc.name}: $tweetText") } } |
this 永远都在,同时 abc 与 this 是完全一样的效果。
注(2018-02-14): 这个语法只是用作 this 别名的话,后面可以不用接类型,例如
|
1 2 3 4 |
trait Tweeter { abc => .... //代码中 abc 就是 this 的别名,它们是等效的 } |
如果在声明 VerifiedTweeter 类只是混入 Tweeter 特质会怎么样呢?以下两种声明都将产生同样的编译错误
如果 User 也是一个 trait,那么声明 VerifiedTweeter1 时可以同时混入 User, 即
|
1 |
trait VerifiedTweeter1 extends Tweeter with User |
由于前面 User 也是一个类,所以需要让 mixin Tweeter 的类继承自 User , 就是
|
1 2 3 |
class VerifiedTweeter(val username: String) extends User(username) with Tweeter { } |
self-type 可以指定多重类型,那么声明子类型或创建实例时也要符合多种类型
|
1 2 3 4 5 6 7 8 9 10 11 |
trait User trait Animal trait Tweeter { this: User with Animal => } class VerifiedTweeter extends Tweeter with User with Animal //直接创建实例 new Tweeter with User with Animal |
还有一种结构类型的 self-type, 更像是匿名类型的 self-type, 不是指定类型名而是类型必须实现的方法,例如
this: {def say: Unit} =>
要求在 Tweeter 中必须实现该方法,如
|
1 2 3 4 5 6 7 8 9 10 11 12 |
class Tweeter extends User { def say: Unit = { println("say something") } } //或者创建匿名的 User 类及实例 val user = new User { def say: Unit = { println("say something") } } |
最后,注意一下 this: User => 这个语法后不能用大括号括起后续的代码
|
1 2 3 4 5 6 7 |
trait Tweeter { this: User => { def tweet(tweetText: String) = { println(s"$name: $tweetText") } } } |
以上代码编译没有问题,但创建的 Tweeter 实例是看不到 tweet(...) 方法的。
链接:
本文链接 https://yanbin.blog/scala-self-type-understanding/, 来自 隔叶黄莺 Yanbin Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

