Объекты Пакета
Info: JavaScript is currently disabled, code tabs will still work, but preferences will not be remembered.
Часто бывает удобно иметь определения, доступные для всего пакета,
когда не нужно придумывать имя для оболочки object, которая их содержит.
Scala 2 предоставляет объекты пакета (package objects) в виде удобного контейнера, общего для всего пакета.
Объекты пакета могут содержать произвольные виды выражений, а не только переменные и методы. Например, они часто используются для хранения псевдонимов типа и наборов неявных преобразований доступных всему пакету. Объекты пакета могут также наследоваться от классов и трейтов Scala.
В будущей версии Scala 3 объекты пакета будут удалены в пользу определений верхнего уровня.
По соглашению, исходный код объекта пакета обычно помещается в файл под названием package.scala.
Каждому пакету разрешено иметь один объект пакета. Любые выражения, содержащиеся в объекте пакета, считаются членами самого пакета.
В Scala 3 любое определение может быть объявлено на верхнем уровне пакета. Например, классы, перечисления, методы и переменные.
Любые определения, размещенные на верхнем уровне пакета, считаются членами самого пакета.
В Scala 2 верхнеуровневый метод, определения типов и переменных должны были быть заключены в объект пакета. Их все еще можно использовать в Scala 3 для обратной совместимости. Вы можете увидеть, как они работают, переключая вкладки.
См. пример ниже. Предположим, есть старший класс Fruit и три наследуемых от него объекта Fruit в пакете.
gardening.fruits:
// в файле gardening/fruits/Fruit.scala
package gardening.fruits
case class Fruit(name: String, color: String)
object Apple extends Fruit("Apple", "green")
object Plum extends Fruit("Plum", "blue")
object Banana extends Fruit("Banana", "yellow")
Теперь предположим, что мы хотим поместить переменную planted и метод showFruit непосредственно в пакет gardening.
Вот как это делается:
// в файле gardening/fruits/package.scala
package gardening
package object fruits {
val planted = List(Apple, Plum, Banana)
def showFruit(fruit: Fruit): Unit = {
println(s"${fruit.name}s are ${fruit.color}")
}
}
// в файле gardening/fruits/package.scala
package gardening.fruits
val planted = List(Apple, Plum, Banana)
def showFruit(fruit: Fruit): Unit =
println(s"${fruit.name}s are ${fruit.color}")
Для примера, следующий объект PrintPlanted импортирует planted и showFruit точно так же, как с вариантом импорта класса Fruit,
используя групповой стиль импорта пакета gardening.fruits:
// в файле PrintPlanted.scala
import gardening.fruits._
object PrintPlanted {
def main(args: Array[String]): Unit = {
for (fruit <- planted) {
showFruit(fruit)
}
}
}
// в файле PrintPlanted.scala
import gardening.fruits.*
@main def printPlanted(): Unit =
for fruit <- planted do
showFruit(fruit)
Объединение нескольких определений на уровне пакета
Часто в вашем проекте может быть несколько повторно используемых определений, заданных в различных модулях, которые вы хотите агрегировать на верхнем уровне пакета.
Например, некоторые вспомогательные методы в трейте FruitHelpers
и некоторые псевдонимы терминов/типов в свойстве FruitAliases.
Вот как вы можете разместить все их определения на уровне пакета fruit:
Объекты пакета ведут себя также, как и любые другие объекты. Это означает, что вы можете использовать наследование, при этом сразу нескольких трейтов:
package gardening
// `fruits` наследует свои элементы от родителей.
package object fruits extends FruitAliases with FruitHelpers
В Scala 3 предпочтительно использовать export для объединения членов из нескольких объектов в единую область видимости.
Здесь мы определяем приватные объекты, которые смешиваются с вспомогательными трейтами,
а затем экспортируют их элементы на верхнем уровне:
package gardening.fruits
private object FruitAliases extends FruitAliases
private object FruitHelpers extends FruitHelpers
export FruitHelpers.*, FruitAliases.*