Пакетные объекты - PullRequest
       1

Пакетные объекты

89 голосов
/ 04 августа 2010

Что такое объекты пакета, не столько концепция, сколько их использование?

Я пытался заставить пример работать, и единственная форма, которую я получил, была следующей:

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 { ... }

также не разрешено.

Похоже, что объект пакета должен быть объявлен в непосредственном родительском пакете, и, если написано, как указано выше, требуется форма объявления пакета в скобках.

Они общего пользования? Если да, то как?

Ответы [ 4 ]

124 голосов
/ 04 августа 2010

Обычно вы помещаете ваш объект пакета в отдельный файл с именем 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.

56 голосов
/ 04 августа 2010

Хотя ответ Морица точен, еще одна вещь, на которую следует обратить внимание, это то, что объекты пакета являются объектами. Среди прочего, это означает, что вы можете создать их из черт, используя смешанное наследование. Пример Морица можно записать как

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 - это конкретные черты, содержащие псевдонимы удобных типов. Все эти черты могут быть повторно использованы многими различными объектами пакета.

7 голосов
/ 04 августа 2010
2 голосов
/ 12 июня 2019

Основной вариант использования для объектов пакета - когда вам нужны определения в различных местах внутри вашего пакета, а также вне пакета, когда вы используете API, определенный пакетом.

Не так с Scala 3 , выпуск которого запланирован на середину 2020 года, на основе Дотти , как вздесь :

Определения верхнего уровня

Все типы определений могут быть записаны на верхнем уровне.
Объекты пакета больше не требуются, будут исключены.

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)
...