Scala 2.8 で追加されたパッケージオブジェクト


以下のドキュメントのままです
http://www.scala-lang.org/docu/files/packageobjects/packageobjects_0.html

パッケージオブジェクトとは

2.8 以前のScalaでは、パッケージの中にはクラスとトレイト、そしてスタンドアロンオブジェクトが定義できました。これらはパッケージのトップレベルに配置することのできるモノの一般的な定義でした。しかし Scala 2.8 ではこの制限がなくなっています。クラス内に置くことのできるどんな定義でもパッケージのトップレベル要素として定義できるようになりました。もし全パッケージをまたいで使いたいヘルパーメソッドがあった場合、パッケージのトップレベルに置くことができます。

パッケージオブジェクトの定義

これを実現するには package object の定義を追加します。それぞれのパッケージは、1つのパッケージオブジェクトを持つことができます。パッケージオブジェクト内に定義されたどんな定義も、パッケージ自身のメンバとして扱われます。

以下に例を示します。最初のFruitクラスと3つのFruitオブジェクトは gardening.fruits パッケージに属します。

// gardening/fruits/Fruit.scala
package gardening.fruits
case class Fruit(name: String, color: String)
object apple extends Fruit("Apple", "green")
object plum extends Fruit("Plum", "blue")
object banana extends Fruit("Banana", "yellow") 

ここで、planted という変数と showFruit メソッドを gardening パッケージの階層内に配置したいとすると、以下のようにすることができます。

// in file gardening/fruits/package.scala
package gardening
package object fruits {
  val planted = List(apple, plum, banana)               
  def showFruit(fruit: Fruit) {
    println(fruit.name +"s are "+ fruit.color)
  }
}


gardening/fruits/package.scala ファイルは gardening.fruits パッケージのためのパッケージオブジェクトを持ちます。構文的にはパッケージオブジェクトは単純なオブジェクトの定義のように見えます。唯一の違いは package キーワードが含まれていることがであり、この点が単純なオブジェクト定義との違いとなります。カーリーブレス内にはどのような定義でも含ませることができます。上記例ではパッケージオブジェクトはplantedという変数とshowFruit というユーティリティメソッドが含まれています。

パッケージオブジェクトの利用

この定義を使えば、同じパッケージにあるどんのなコードでも、クラスをインポートするのと同じようにインポートすることができます。例えば、以下の PrintPlanted オブジェクトでは gardening.fruits パッケージをワイルドカードインポートすることで planted と showFruit をインポートしています。これは Fruit クラスをインポートするのと全く同じように行われています。

// in file PrintPlanted.scala
import gardening.fruits._
object PrintPlanted {
  def main(args: Array[String]) {
    for (fruit: Fruit <- fruits.planted) {
      showFruit(fruit)
    }
  }
}


パッケージオブジェクトは、変数とメソッド定義だけではなく、任意の定義を含むことができます。例えば、パッケージワイドな型エイリアスや暗黙の型変換を保持するために多用されます。パッケージオブジェクトはScalaクラスとトレイトを継承することさえできます。