浏览Scala源代码,我偶然发现Enumeration.scala
:
abstract class Enumeration(initial: Int, names: String*) extends Serializable {
thisenum =>
def this() = this(0)
def this(names: String*) = this(0, names: _*)
/* Note that `readResolve` cannot be private, since otherwise
the JVM does not invoke it when deserializing subclasses. */
protected def readResolve(): AnyRef = thisenum.getClass.getField("MODULE$").get()
// ... SNIP ...
}
thisenum =>
是什么?我在“Scala编程”一书中找不到任何信息。
答案 0 :(得分:7)
Scala编程2d版本在第29.4节“将模块拆分为特征”一节中介绍了自我类型的概念:
SimpleFoods特征可能看起来像:
trait SimpleFoods {
object Pear extends Food("Pear")
def allFoods = List(Apple, Pear)
def allCategories = Nil
}
到目前为止一直很好,但不幸的是,如果你试图定义一个像这样的SimpleRecipes特征,就会出现问题:
trait SimpleRecipes { // Does not compile
object FruitSalad extends Recipe(
"fruit salad",
List(Apple, Pear), // Uh oh
"Mix it all together."
)
def allRecipes = List(FruitSalad)
}
这里的问题是
Pear
位于与其不同的特征中 使用它,因此超出了范围 编译器不知道SimpleRecipes
只与SimpleFoods
混合在一起 但是,有一种方法可以告诉编译器。 Scala为这种情况提供了自我类型 从技术上讲,无论何时在类中提及,自我类型都是假设的类型 实际上,一个自我类型指定了混合特征的任何具体类的要求 如果你有一个只在与另一个特征或特征混合时使用的特性,那么你可以指定应该假设其他特征。
在目前的情况下,只需指定SimpleFoods
的自我类型就足够了,如下所示:
trait SimpleRecipes {
this: SimpleFoods =>
object FruitSalad extends Recipe(
"fruit salad",
List(Apple, Pear), // Now Pear is in scope
"Mix it all together."
)
def allRecipes = List(FruitSalad)
}
鉴于新的自我类型,
Pear
现已可用 隐含地,对Pear
的引用被认为是this.Pear
这是安全的,因为在SimpleRecipes
中混合的任何具体类也必须是SimpleFoods
的子类型,这意味着Pear
将成为其成员。
抽象的子类和特征不必遵循此限制,但由于它们无法使用new进行实例化,因此this.Pear
引用不会失败
答案 1 :(得分:2)
这是自我类型。请参阅Scala第二版中的编程第29.4节。我不认为它在第一版中有所涉及,而且我无论如何也无法查找。
在这个示例中,所做的就是确保thisenum
从Enumeration
的内部引用this
的{{1}}。
答案 2 :(得分:1)
这不是自我类型注释,而只是此的别名,因为问题中没有涉及类型要求,请查看此SO question
答案 3 :(得分:0)
它确实是自我类型注释。请参阅官方的Scala规范:
https://scala-lang.org/files/archive/spec/2.13/13-syntax-summary.html
根据此规范,其上下文无关的EBNF语法为:
SelfType ::= id [‘:’ Type] ‘=>’ | ‘this’ ‘:’ Type ‘=>’
因此,基本上,这意味着SelfType具有两种基本形式。在一种形式中,您可以使用带或不带Type的ID。另外,您可以使用this
,但必须将其与Type一起使用。
关于本书的问题,可以在Scala Second Edition中的Programming的29.4节中找到。但是,请记住,书籍可能很快就会过时,因此您需要参考规范。