Что такое объекты пакета, не столько концепция, сколько их использование?
Я попытался заставить пример работать, и единственная форма, которую я получил, была следующая:
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 { ... }
также запрещено.
Кажется, что объект пакета должен быть объявлен в непосредственном родительском пакете, и, если он написан, как указано выше, требуется форма объявления пакета, разделенная фигурными скобками.
Они широко используются? Если да, то как?
Ответы:
Обычно вы помещаете свой объект пакета в отдельный файл, вызываемый
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
.источник
org
илиcom
пакет верхнего уровня своим объектом пакета, если вы хотите, чтобы он принадлежал вашему собственному корневому пакету, напримерorg.foo
. Я считаю, что если позволить определению быть прямо под пакетом, частью которого оно должно быть, было бы немного более подходящим языковым интерфейсом api.Хотя ответ Морица точен, следует отметить еще одну вещь: объекты пакета являются объектами. Помимо прочего, это означает, что вы можете создавать их из признаков, используя смешанное наследование. Пример Морица можно было бы записать как
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 = // ... }
Здесь управление версиями - это абстрактная черта, которая гласит, что объект пакета должен иметь метод «версии», тогда как JodaAliases и JavaAliases - это конкретные черты, содержащие удобные псевдонимы типов. Все эти черты могут быть повторно использованы множеством различных объектов пакета.
источник
Можно поступить хуже, чем сразу обратиться к источнику. :)
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
источник
Не так с Scala 3 , который планируется выпустить в середине 2020 года на основе Dotty , как здесь :
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)
источник