web-dev-qa-db-ja.com

パッケージオブジェクト

パッケージオブジェクトとは何ですか?概念ではなく、その使用法ですか?

私は例を動作させようとしましたが、動作するようになった唯一のフォームは次のとおりでした:

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

も許可されていません。

パッケージオブジェクトは直接の親パッケージで宣言する必要があり、上記のように記述した場合は、中括弧で区切られたパッケージ宣言フォームが必要です。

それらは一般的に使用されていますか?もしそうなら、どのように?

89
Don Mackenzie

通常、パッケージオブジェクトは、対応するパッケージ内の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クライアントに要求することを防ぐことができます。スカラスイングでは、書く必要があります

import swing._
import Swing._

onEDTTuple2からDimensionへの暗黙的な変換のようなすべての長所を持ちます。

125
Moritz

Moritzの答えはスポットオンですが、注意すべきもう1つの点は、パッケージオブジェクトがオブジェクトであるということです。とりわけ、これは、ミックスイン継承を使用して、特性からそれらを構築できることを意味します。 Moritzの例は、

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は便利なタイプエイリアスを含む具体的な特性です。これらの特性はすべて、さまざまなパッケージオブジェクトで再利用できます。

56
Dave Griffith
7
Alex Cruise

パッケージオブジェクトの主な使用例は、パッケージで定義された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)
3
VonC