问题描述
class S {
case class A(a: Int)
}
abstract class R(val s: S) {
type T1 = R.this.s.A
type T2 = s.A
implicitly[T1 =:= T2] // compiles
type T3 = R.this.type
type T4 = this.type
implicitly[T3 =:= T4] // compiles
val v1 = R.this // v1 == `this`
val v2 = R.this.s // v2 == `s`
}
看起来 .this
部分没有任何影响。提出一个具体的问题:
您什么时候使用 .this
?
解决方法
这对内部类很重要。例如
class Outer(val x: Int) {
class Inner(val x: Int) {
def outer_this = Outer.this.x
def inner_this = this.x // or just x
}
}
val outer = new Outer(0)
val inner = new outer.Inner(1)
println(inner.outer_this) // 0
println(inner.inner_this) // 1
每个 Outer.Inner
实例“属于”一个特定的 Outer
实例,并且可以将该实例称为 Outer.this
。 x
中的 Inner
本身是指它自己的属性,因此如果您需要封闭实例的 x
属性,请编写 Outer.this.x
。
一个规则是 Scala 从不推断单例类型 this.type
。例如首先考虑它的机制
scala> trait Foo {
| type T
| def f() = this // we left out the return type to see what Scala will infer
| }
// defined trait Foo
scala> new Foo { type T = String }
val res0: Foo{T = String} = anon$1@6d3ad37a
scala> res0.f()
val res1: Foo = anon$1@6d3ad37a
注意 res1
的返回类型是 Foo
而不是 Foo { type T = String }
,所以我们丢失了一些类型信息
scala> val x: res1.T = ""
1 |val x: res1.T = ""
| ^^
| Found: ("" : String)
| Required: res1.T
注意编译器不知道 res1.T
实际上是一个 String
。因此,编译器没有推断出单例类型 this.type
,它具有所有类型信息,包括实例化的类型成员 T
scala> trait Foo {
| type T
| def f(): this.type = this
| }
// defined trait Foo
scala> new Foo { type T = String }
val res2: Foo{T = String} = anon$1@7d381eae
scala> res2.f()
val res3: Foo{T = String} = anon$1@7d381eae
scala> val x: res3.T = ""
val x: res3.T = ""
注意在我们显式声明单例返回类型 this.type
之后,编译器如何知道 T
是 String
。
这是另一个机械示例,说明编译器不会推断单例类型 this.type
scala> trait Foo {
| def f() = this // let inference do its thing
| }
// defined trait Foo
scala> trait Bar {
| def g() = 42
| }
// defined trait Bar
scala> trait Bar extends Foo {
| def g(): Int = 42
| }
// defined trait Bar
scala> new Bar {}
val res5: Bar = anon$1@6a9a6a0c
scala> res5.f()
val res6: Foo = anon$1@6a9a6a0c
scala> res6.g()
1 |res6.g()
|^^^^^^
|value g is not a member of Foo
注意 f()
调用是如何输入到 Foo
而不是预期的 Bar
。另一方面,如果我们提供显式的单例返回类型 this.type
那么
scala> trait Foo {
| def f(): this.type = this
| }
// defined trait Foo
scala> trait Bar extends Foo {
| def g(): Int = 42
| }
// defined trait Bar
scala> new Bar {}
val res7: Bar = anon$1@4707d60a
scala> res7.f()
val res8: Bar = anon$1@4707d60a
scala> res8.g()
val res9: Int = 42
我们看到 f()
调用输入到 Bar
。
那些是机制,但实际应用呢?我知道的两种用途是: