Объекты пакета
Что такое объекты пакета, а не столько понятие, сколько их использование?
Я попытался получить пример работы, и единственная форма, которую я получил, была следующей:
package object investigations {
val PackageObjectVal = "A package object val"
}
package investigations {
object PackageObjectTest {
def main(args: Array[String]) {
println("Referencing a package object val: " + PackageObjectVal)
}
}
}
Наблюдения, которые я сделал до сих пор:
package object _root_ { ... }
запрещен (что разумно),
package object x.y { ... }
также запрещен.
Кажется, что объект пакета должен быть объявлен в непосредственном родительском пакете и, если он написан, как указано выше, требуется форма декларации пакета с разделителями.
Они широко используются? Если да, то как?
Ответы
Ответ 1
Обычно вы помещаете свой пакетный объект в отдельный файл с именем package.scala
в пакет, которому он соответствует. Вы также можете использовать синтаксис вложенного пакета, но это довольно необычно.
Основной вариант использования для объектов пакета - это когда вам нужны определения в разных местах вашего пакета, а также вне пакета, когда вы используете API, определенный пакетом. Вот пример:
// file: foo/bar/package.scala
package foo
package object bar {
// package wide constants:
def BarVersionString = "1.0"
// or type aliases
type StringMap[+T] = Map[String,T]
// can be used to emulate a package wide import
// especially useful when wrapping a Java API
type DateTime = org.joda.time.DateTime
type JList[T] = java.util.List[T]
// Define implicits needed to effectively use your API:
implicit def a2b(a: A): B = // ...
}
Теперь определения внутри этого объекта пакета доступны внутри всего пакета foo.bar
. Кроме того, определения импортируются, когда кто-то из этого пакета импортирует foo.bar._
.
Таким образом вы можете запретить требовать от клиента API выдачи дополнительных импортных ресурсов для эффективной работы с вашей библиотекой. в scala -swing вам нужно написать
import swing._
import Swing._
чтобы иметь все доброту, как onEDT
, и неявные преобразования от Tuple2
до Dimension
.
Ответ 2
В то время как ответ Морица спот, еще одна вещь, которую следует отметить, это объекты пакета - объекты. Помимо прочего, это означает, что вы можете создавать их из свойств, используя наследование смешения. Пример Морица можно записать как
package object bar extends Versioning
with JodaAliases
with JavaAliases {
// package wide constants:
override val version = "1.0"
// or type aliases
type StringMap[+T] = Map[String,T]
// Define implicits needed to effectively use your API:
implicit def a2b(a: A): B = // ...
}
Здесь Versioning - это абстрактный признак, в котором говорится, что объект пакета должен иметь метод "версия", а JodaAliases и JavaAliases - это конкретные черты, содержащие удобные псевдонимы типов. Все эти черты могут быть повторно использованы многими различными объектами пакета.
Ответ 3
Вы могли бы сделать хуже, чем идти прямо к источнику.:)
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala/package.scala
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala/collection/immutable/package.scala
Ответ 4
Основной вариант использования для объектов пакета - когда вам нужны определения в различных местах внутри вашего пакета, а также вне пакета, когда вы используете API, определенный пакетом.
Не так со Scala 3, выход которой запланирован на середину 2020 года на основе Dotty, как здесь:
Определения Toplevel
Все виды определений могут быть написаны на верхнем уровне.
Объекты пакета больше не нужны, будут сняты с производства.
package p
type Labelled[T] = (String, T)
val a: Labelled[Int] = ("count", 1)
def b = a._2
def hello(name: String) = println(i"hello, $name)