В издании «Программирование в 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 предоставляет тип self именно для этой ситуации.
Технически тип self является предполагаемым типом для этого всякий раз, когда он упоминается в классе .
Прагматически, , который указывает тип selfтребования к любому конкретному классу, к которому эта черта примешивается .
Если у вас есть черта, которая используется только когда смешана с другой чертой или чертами, вы можете указать, что эти другие черты должны быть приняты.
В данном случае достаточно указать собственный тип 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)
}
С учетом нового типа self, Pear
теперь доступно.
Неявно, ссылка на Pear
считается this.Pear
.
Это безопасно, потому что любой конкретный класс, который смешивается в SimpleRecipes
, также должен быть подтипом SimpleFoods
, что означает, чтоPear
будет членом.
Абстрактные подклассы и признаки не должны следовать этому ограничению, но, поскольку они не могут быть созданы с новым, нет риска, что ссылка this.Pear
будетЯ терплю неудачу