开发者

Right arrow in class body in Scala

Looking through the Scala source code, I stumbled across 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 ...

}

What is the the thisenum => for? I couldn't find any info in the "Programming in Scala" book.


The Programming in Scala 2d edition introduce the concept of self type in the section 29.4 "Splitting modules into trait":

The SimpleFoods trait could look as:

trait SimpleFoods {
  object Pear extends Food("Pear")
  def allFoods = List(Apple, Pear)
  def allCategories = Nil
}

So far so good, but unfortunately, a problem arises if you try to define a SimpleRecipes trait like this:

trait SimpleRecipes { // Does not compile
  object FruitSalad extends Recipe(
    "fruit salad",
    List(Apple, Pear), // Uh oh
    "Mix it all together."
  )
  def allRecipes = List(FruitSalad)
}

The problem here is that Pear is located in a different trait from the one that uses it, so it is out of scope.
The compiler has no idea that SimpleRecipes is only ever mixed together with SimpleFoods.
There is a way you can tell this to the compiler, however. Scala provides the self type for precisely this situation.
Technically, a self type is an assumed type for this whenever this is mentioned within the class.
Pragmatically, a self type specifies the requirements on any concrete class the trait is mixed into.
If you have a trait that is only ever used when mixed in with another trait or traits, then you can specify that those other traits should be assumed.
In the present case, it is enough to specify a self type of SimpleFoods, as shown:

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)
}

Given the new self type, Pear is now available.
Implicitly, the reference to Pear is thought of as this.Pear.
This is safe, because any concrete class that mixes in SimpleRecipes must also be a subtype of SimpleFoods, which means that Pear will be a member.
Abstract subclasses and traits do not have to follow this restriction, but since they cannot be instantiated with new, there is no risk that the this.Pear reference will fail


It's a self type. See section 29.4 of Programming in Scala Second Edition. I don't think it was covered on the first edition, and I don't have one around to lookup anyway.

All that did, in this example, was make sure thisenum would refer to Enumeration's this from any inner of Enumeration.


It is not a self type annotation, but just an alias for this since there is no type requirement involved in the question, check this SO question


It is indeed self type annotation. See the official Scala specification:

https://scala-lang.org/files/archive/spec/2.13/13-syntax-summary.html

According to this specification, its context free EBNF syntax is:

SelfType    ::=  id [‘:’ Type] ‘=>’
                |  ‘this’ ‘:’ Type ‘=>’

So, basically, this means SelfType has two basic forms. In one form, you can use an id with or without Type. In the other, you can use this but it must be accompanied with a Type.

As for your question regarding the book, you can find it in section 29.4 of Programming in Scala Second Edition. However, remember that books can be quickly out of date, so you need to refer to the specification.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜