3

阅读这些 帖子让我觉得我至少在某种程度上理解了自我类型。

所以我创建了一个按预期失败的示例:

scala> trait A { val v = "a" }
defined trait A

scala> trait B { this :A => ; var v = "" ; this.v = "b" }
<console>:6: error: reassignment to val
       trait B { this :A => ; var v = "" ; this.v = "b" }
                                                  ^

自我类型的“this”遮蔽了 B 的“this”——看起来很奇怪,但很有意义。

那么,给自我类型起一个不同的名字似乎是明智的。我这样做了,很惊讶:

scala> trait C { a :A => ; var v = "" ; this.v = "c" }
<console>:6: error: reassignment to val
       trait C { a :A => ; var v = "" ; this.v = "c" }
                                               ^

还是有阴影???

更改“本地”变量的名称可以编译,这是有道理的:

scala> trait D { a :A => ; var w = "" ; this.w = a.v }
defined trait D

(并且可以选择使用 self 类型名称来明确使用哪个“v”。)

好的。这意味着以下应该失败?

scala> trait E { this :A => ; var w = "" ; this.w = this.v }
defined trait E

嗯?这是哪个?:-(

那么......命名自我类型有什么意义吗?无论如何,“这个”似乎最终都被遮蔽了。

或者这是范围规则的边缘情况,其中自我类型的“this”优先于特征的“this”——并且应该避免对相关特征中的事物使用相同的名称?

4

2 回答 2

8

您的问题不是 self 类型的名称(在所有示例中,备用 self 类型名称都指代相同的事物并具有相同的类型,即“和this的最大下限”[§5.1,Scala 语言Spec]),但您尝试再次定义具有相同名称的字段而不显式覆盖它。BA

看一个更简单的例子:

trait A { val v = "a" }
trait B { this: A =>
  var v = "b"
}

new A with B {} // does not compile

<console>:9: error: overriding value v in trait A$class of type java.lang.String;
 variable v in trait B$class of type java.lang.String needs `override' modifier
   new A with B {}

因此,即使您在定义 时没有遇到错误B,您也根本无法使用它。

这会起作用

trait A { val v = "a" }
trait B { this:A => override val v = "b"  }

new A with B {}

在这里,您明确地覆盖了A's vin B。(请注意,这new B with A {}会失败,因为B需要排在最后。)此外,它必须是 aval因为在大多数情况下,您不能真正覆盖vars 并且不能使用 a 覆盖其他东西var

通常,在这些简单的情况下,您不应该关心 self 类型的名称。只要您不在 内部创建另一个特征或类B,两者this以及您所称的自类型变量都将指向同一事物。不会有阴影。如果你有一个新的 trait inside B,并且你需要引用B这个 trait 内部的实例,你需要为你的 self-type 取另一个名字。

考虑这个

trait B { this =>
  val v = "b"
  trait C {
    val v = "c"
    println(this.v)
  }
  new C {}
}
new B {}

// prints c

与这个:

trait B { self =>
  val v = "b"
  trait C {
    val v = "c"
    println(this.v)  // prints c
    println(self.v)  // prints b
  }
  new C {}
}
new B {}

(如果没有任何进一步的类型注释,您可以省略this此示例中的所有内容。)

于 2011-01-19T23:19:18.183 回答
4

自我类型并没有掩盖这一点。它就是这种类型。(实际上 self-type 是交集:在 trait A { self: B => ...} 中,this 的类型是 A 和 B。)您可以在给 self 类型时提供一个名称,以便于消除多个 thises 的歧义,但是由于您在任何代码片段中都不会有超过一个 this ,所以它是无关紧要的。

[...]自我类型的“this”优先于特质的“this”

你在好几个地方都有同样的想法,这个不止一个。没有。只有这个。在您声明另一个模板之前,您不会得到另一个 this。

trait A {
  self1 =>

  trait B {
    self2 =>

    // Here unqualified this refers to B and not A, so "self1" is useful.
    // ...but not necessary, because A.this.xxx does the same thing.
  }
}
于 2011-01-20T07:50:02.197 回答