Пакетные объекты
Что такое объекты пакета, не столько концепция, сколько их использование?
Я попытался заставить пример работать, и единственная форма, которую я получил, была следующая:
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 { ... }
также запрещено.
Кажется, что объект пакета должен быть объявлен в непосредственном родительском пакете и, если написано, как указано выше, требуется форма объявления пакета с разделителями-скобками.
Они в общем пользовании? Если так, то как?
3 ответа
Обычно вы помещаете объект пакета в отдельный файл с именем 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
,
Хотя ответ Морица точен, еще одна вещь, на которую следует обратить внимание, это то, что объекты пакета являются объектами. Среди прочего, это означает, что вы можете построить их из черт, используя смешанное наследование. Пример Морица может быть записан как
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 - это абстрактная черта, которая говорит, что объект пакета должен иметь метод "version", в то время как JodaAliases и JavaAliases - это конкретные черты, содержащие псевдонимы удобных типов. Все эти черты могут быть повторно использованы многими различными объектами пакета.
Основной вариант использования объектов пакета - это когда вам нужны определения в различных местах внутри вашего пакета, а также за пределами пакета, когда вы используете API, определенный пакетом.
Не так с 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)
Вы могли бы сделать хуже, чем идти прямо к источнику.:)
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala/package.scala