アットウィキロゴ

28-pkgobj-a

「28-pkgobj-a」の編集履歴(バックアップ)一覧はこちら

28-pkgobj-a - (2011/04/07 (木) 09:54:37) の1つ前との変更点

追加された行は緑色になります。

削除された行は赤色になります。

* パッケージオブジェクト (package_objects) #center(){Martin_Odersky, Lex Spoon} #center(){September 15, 2010} 2.8 まで、あなたがパッケージに入れることができた唯一のものはクラス、トレイトとスタンドアローンのオブジェクトでした。パッケージのトップレベルに置かれるべき最もよく使われる定義があります。しかし Scala プログラミング言語バージョン 2.8 にできることは、それに留まりません。クラス内のどのような種類の定義も、パッケージのトップレベルに置けます。もしパッケージ全体のスコープに入れたいヘルパーメソッドがあるなら、どうぞパッケージのトップレベルの適切な場所に入れてください。 そうするには、パッケージオブジェクトの中に定義を入れます。各パッケージは 1 つのパッケージオブジェクトを持てます。パッケージオブジェクト中に置かれたどのような定義も、パッケージそれ自身のメンバーとみなされます。 次に例をリストします。まず、パッケージ gardening.fruits にクラス Fruit と 3 つの Fruit オブジェクトがあるとします。: // ファイル 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") 今度は、パッケージ gardening 中に直接、変数 planted とメソッド showFruit を置きたいとします。次の様にします。: // ファイル 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 上のワイルドカード・インポートを使って、クラス Fruit をインポートするのと全く同じやり方で planted と showFruit をインポートします。 // ファイル PrintPlanted.scala 中 import gardening.fruits._ object PrintPlanted { def main(args: Array[String]) { for (fruit: Fruit <- fruits.planted) { showFruit(fruit) } } } パッケージオブジェクトは、変数やメソッド定義だけではなく、任意の定義を含むことができます。例えば、それらはパッケージ全体にわたる型エイリアスや暗黙の変換を保持するのにも頻繁に使われます。パッケージオブジェクトは Scala クラスやトレイトの継承さえできます。 - &link_anchor(where){パッケージオブジェクトをどこに入れるか} - &link_anchor(packageobj){Scala パッケージオブジェクト} - &link_anchor(restrictions){制限と次にすること} - &link_anchor(contents){目次} - &link_anchor(navigation){ナビゲーション} #center(){==========================================} &aname(where,option=nolink){ } ** パッケージオブジェクトをどこに入れるか (Where to put package_objects) Package objects are compiled to class files named package.class, which are the located in the directory of the package that they augment. パッケージオブジェクトは、package.class という名前のクラスファイルへコンパイルされ、増やしたパッケージのディレクトリ中に置かれます。ですから、パッケージオブジェクト fruits は、完全修飾された名前 gardening.fruit.package をもつクラスへコンパイルされます(package は Java と Scala の予約語ですが、JVM レベルではクラス名の一部としても使えます)。Scala では、バッククオートを使って、直接これを定義することさえできます。: package gardening.fruits object `package` { ... } ソースファイルと同じ記法を使えるのは便利です。このように通常、パッケージオブジェクト gardening.fruits のソースファイルは、gardening/fruits ディレクトリ中にある package.scala と名付けたファイルへ入れます。 #center(){==========================================} &aname(packageobj,option=nolink){ } ** Scala パッケージオブジェクト 標準的な Scala パッケージもそのパッケージオブジェクトを持っています。すべての Scala ファイル中に scala._ が自動的にインポートされるので、このオブジェクトの定義は前置子なしで利用できます。 次は、このパッケージオブジェクトで最も重要な定義です。ご覧のように、このオブジェクトの主目的は、サブパッケージ中にネストされた多数のよく使われる定義を Scala パッケージから利用可能にすることです。このようにして、我々はアクセスの便宜と論理構造を分離します。例えば、List 型は大変よく使うので、これを Scala パッケージ中に置いて、インポートあるいは名前修飾なしでアクセスできるようにすることは、意味があります。他方、List はイミュータブルなコレクションクラスですから、論理的にはパッケージ scala.collection.immutable に属します。 Using package_objects, one can have both a logical structure and fast access . パッケージオブジェクトを使って、論理構造と高速アクセスを両立できます。 package object scala { // コレクションクラスの型と値のエイリアス type TraversableOnce[+A] = scala.collection.TraversableOnce[A] type Traversable[+A] = scala.collection.Traversable[A] val Traversable = scala.collection.Traversable type Iterable[+A] = scala.collection.Iterable[A] val Iterable = scala.collection.Iterable type Seq[+A] = scala.collection.Seq[A] val Seq = scala.collection.Seq type IndexedSeq[+A] = scala.collection.IndexedSeq[A] val IndexedSeq = scala.collection.IndexedSeq type Iterator[+A] = scala.collection.Iterator[A] val Iterator = scala.collection.Iterator type BufferedIterator[+A] = scala.collection.BufferedIterator[A] type List[+A] = scala.collection.immutable.List[A] val List = scala.collection.immutable.List val Nil = scala.collection.immutable.Nil type ::[A] = scala.collection.immutable.::[A] val :: = scala.collection.immutable.:: type Stream[+A] = scala.collection.immutable.Stream[A] val Stream = scala.collection.immutable.Stream val #:: = scala.collection.immutable.Stream.#:: type Vector[+A] = scala.collection.immutable.Vector[A] val Vector = scala.collection.immutable.Vector type StringBuilder = scala.collection.mutable.StringBuilder type Range = scala.collection.immutable.Range val Range = scala.collection.immutable.Range // scala.math.* へ移された数値型 type BigDecimal = scala.math.BigDecimal val BigDecimal = scala.math.BigDecimal type BigInt = scala.math.BigInt val BigInt = scala.math.BigInt type Equiv[T] = scala.math.Equiv[T] type Fractional[T] = scala.math.Fractional[T] type Integral[T] = scala.math.Integral[T] type Numeric[T] = scala.math.Numeric[T] val Numeric = scala.math.Numeric type Ordered[T] = scala.math.Ordered[T] val Ordered = scala.math.Ordered type Ordering[T] = scala.math.Ordering[T] val Ordering = scala.math.Ordering type PartialOrdering[T] = scala.math.PartialOrdering[T] type PartiallyOrdered[T] = scala.math.PartiallyOrdered[T] ... } package scala の型エイリアスの大部分に、一緒に同じ名前の値エイリアスがあることにも注意してください。例えば、List クラスの型エイリアスと List オブジェクトの値エイリアスがあります。このようにして、前置子なしでリスト型にアクセスできるだけではなく、List(1,2,3) のような構文でリスト値を生成することもできます。後者の式を分解すると、次になります。 List.apply(1, 2, 3) すなわち、scala.List 値の apply メソッドの呼び出しです。この値は今度は、問題の apply メソッドを定義する scala.collection.immutable.List オブジェクトのエイリアスです。 #center(){==========================================} &aname(restrictions,option=nolink){ } ** 制限と次にすること (Restrictions and things to come) 現在実装されているパッケージオブジェクトには、いくつかの制限があります。第一に、パッケージオブジェクト中のオーバーロードされたメソッドを定義、あるいは継承できません。 Second, you cannot define or inherit a member in a package_object which is also the name of a top-level class_or_object in same package. 第二に、同じパッケージ中でトップレベルのクラスまたはオブジェクトの名前にもなっている、パッケージオブジェクト中のメンバーは定義あるいは継承できません。 我々は近い将来の Scala リリースで、これらの制限がなくなることを期待しています。 興味深い問題は、パッケージ中のトップレベルのクラスまたはオブジェクトの名前が、関連するパッケージオブジェクト中で再定義されたとき何が起きるかです。当面、これは単純に禁じられています。 But if we wanted to allow this, it would make sense to take the definition in the package_object as the public interface of the definition in the package itself. しかしもしこれを許したいなら、パッケージオブジェクト中の定義をパッケージそれ自身の定義の公開インターフェースとみなすことは理にかなっているでしょう。パッケージ内のコードからは、完全な定義を見ることができます。しかしパッケージ外のコードからは、パッケージオブジェクト中で何が定義されているかが見えるだけです。このようにパッケージオブジェクトは、インターフェースと実装を柔軟に組み合わせることを可能にする、かなり先進的なモジュールシステムのバックボーンに発展し得ます。 もちろん、まだすべきことはあり、詳細を練らねばなりません。しかしこれは興味深い可能性を切り開きます。 #center(){==========================================} &aname(contents,option=nolink){ } ** 目次 (Contents) - &link_anchor(where){パッケージオブジェクトをどこに入れるか} - &link_anchor(packageobj){Scala パッケージオブジェクト} - &link_anchor(restrictions){制限と次にすること} - &link_anchor(contents){目次} - &link_anchor(navigation){ナビゲーション} #center(){==========================================} &aname(navigation,option=nolink){ } ** ナビゲーション (Navigation) - &link_anchor(where){パッケージオブジェクトをどこに入れるか} - &link_anchor(packageobj){Scala パッケージオブジェクト} - &link_anchor(restrictions){制限と次にすること} - &link_anchor(contents){目次} - &link_anchor(navigation){ナビゲーション}
* パッケージオブジェクト (package_objects) &bold(){Martin_Odersky, Lex Spoon} &bold(){September 15, 2010} 2.8 まで、あなたがパッケージに入れることができた唯一のものはクラス、トレイトとスタンドアローンのオブジェクトでした。パッケージのトップレベルには最もよく使われる定義が置いてあります。しかし Scala プログラミング言語バージョン 2.8 にできることは、それに留まりません。クラス内のどのような種類の定義も、パッケージのトップレベルに置けます。もしパッケージ全体のスコープに入れたいヘルパーメソッドがあるなら、どうぞパッケージのトップレベルの適切な場所に入れてください。 そうするには、パッケージオブジェクトの中に定義を入れます。各パッケージは 1 つのパッケージオブジェクトを持てます。パッケージオブジェクト中に置かれたどのような定義も、パッケージそれ自身のメンバーとみなされます。 次に例をあげます。まず、パッケージ gardening.fruits にクラス Fruit と 3 つの Fruit オブジェクトがあるとします。: // ファイル 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") 今度は、パッケージ gardening 中に直接、変数 planted とメソッド showFruit を置きたいとします。次の様にします。: // ファイル 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 上のワイルドカード・インポートを使って、クラス Fruit をインポートするのと全く同じやり方で planted と showFruit をインポートします。 // ファイル PrintPlanted.scala 中 import gardening.fruits._ object PrintPlanted { def main(args: Array[String]) { for (fruit: Fruit <- fruits.planted) { showFruit(fruit) } } } パッケージオブジェクトは、変数やメソッド定義だけではなく、任意の定義を含むことができます。例えば、それらはパッケージ全体にわたる型エイリアスや暗黙の変換を保持するのにも頻繁に使われます。パッケージオブジェクトは Scala クラスやトレイトの継承さえできます。 - &link_anchor(where){パッケージオブジェクトをどこに入れるか} - &link_anchor(packageobj){Scala パッケージオブジェクト} - &link_anchor(restrictions){制限事項と次にすること} - &link_anchor(contents){目次} - &link_anchor(navigation){ナビゲーション} #center(){==========================================} &aname(where,option=nolink){ } ** パッケージオブジェクトをどこに入れるか (Where to put package objects) Package objects are compiled to class files named package.class which are the located in the directory of the package that they augment. So the package object fruits would be complied to a class with fully qualified name gardening.fruit.package (Note that, even though package is a reserved word in Java and Scala, it is still allowed as part of a class name on the JVM level. In Scala, you can even define it directly, using backticks: パッケージオブジェクトは、package.class という名前のクラスファイルへコンパイルされ、増やしたパッケージのディレクトリ中に置かれます。ですから、パッケージオブジェクト fruits は、完全修飾された名前 gardening.fruit.package をもつクラスへコンパイルされます(package は Java と Scala の予約語ですが、JVM レベルではクラス名の一部としても使えます)。Scala では、バッククオートを使って、直接これを定義することさえできます。: package gardening.fruits object `package` { ... } ソースファイルと同じ記法を使えるのは便利です。このように通常、パッケージオブジェクト gardening.fruits のソースファイルは、gardening/fruits ディレクトリ中にある package.scala と名付けられたファイルへ入れます。 #center(){==========================================} &aname(packageobj,option=nolink){ } ** Scala パッケージオブジェクト 標準的な Scala パッケージもそのパッケージオブジェクトを持っています。すべての Scala ファイル中に scala._ が自動的にインポートされるので、このオブジェクトの定義は前置子なしで利用できます。 次は、このパッケージオブジェクトで最も重要な定義です。ご覧のように、このオブジェクトの主目的は、サブパッケージ中にネストされた多数のよく使われる定義を Scala パッケージから利用可能にすることです。このようにして、我々はアクセスの便宜と論理構造を分離します。例えば、List 型は大変よく使うので、これを Scala パッケージ中に置いて、インポートあるいは名前修飾なしでアクセスできるようにすることは、意味があります。他方、List はイミュータブルなコレクションクラスですから、論理的にはパッケージ scala.collection.immutable に属します。パッケージオブジェクトを使って、論理構造の維持と高速アクセスの両立ができます。 package object scala { // コレクションクラスの型と値のエイリアス type TraversableOnce[+A] = scala.collection.TraversableOnce[A] type Traversable[+A] = scala.collection.Traversable[A] val Traversable = scala.collection.Traversable type Iterable[+A] = scala.collection.Iterable[A] val Iterable = scala.collection.Iterable type Seq[+A] = scala.collection.Seq[A] val Seq = scala.collection.Seq type IndexedSeq[+A] = scala.collection.IndexedSeq[A] val IndexedSeq = scala.collection.IndexedSeq type Iterator[+A] = scala.collection.Iterator[A] val Iterator = scala.collection.Iterator type BufferedIterator[+A] = scala.collection.BufferedIterator[A] type List[+A] = scala.collection.immutable.List[A] val List = scala.collection.immutable.List val Nil = scala.collection.immutable.Nil type ::[A] = scala.collection.immutable.::[A] val :: = scala.collection.immutable.:: type Stream[+A] = scala.collection.immutable.Stream[A] val Stream = scala.collection.immutable.Stream val #:: = scala.collection.immutable.Stream.#:: type Vector[+A] = scala.collection.immutable.Vector[A] val Vector = scala.collection.immutable.Vector type StringBuilder = scala.collection.mutable.StringBuilder type Range = scala.collection.immutable.Range val Range = scala.collection.immutable.Range // scala.math.* へ移された数値型 type BigDecimal = scala.math.BigDecimal val BigDecimal = scala.math.BigDecimal type BigInt = scala.math.BigInt val BigInt = scala.math.BigInt type Equiv[T] = scala.math.Equiv[T] type Fractional[T] = scala.math.Fractional[T] type Integral[T] = scala.math.Integral[T] type Numeric[T] = scala.math.Numeric[T] val Numeric = scala.math.Numeric type Ordered[T] = scala.math.Ordered[T] val Ordered = scala.math.Ordered type Ordering[T] = scala.math.Ordering[T] val Ordering = scala.math.Ordering type PartialOrdering[T] = scala.math.PartialOrdering[T] type PartiallyOrdered[T] = scala.math.PartiallyOrdered[T] ... } package scala の型エイリアスの大部分に、同じ名前の値エイリアスが一緒にあることにも注意してください。例えば、List クラスの型エイリアスと List オブジェクトの値エイリアスがあります。このようにして、前置子なしでリスト型にアクセスできるだけではなく、List(1,2,3) のような構文でリスト値の生成もできます。後者の式を分解すると、次になります。 List.apply(1, 2, 3) すなわち、scala.List 値の apply メソッドの呼び出しです。この値は今度は、当該の apply メソッドを定義する scala.collection.immutable.List オブジェクトのエイリアスです。 #center(){==========================================} &aname(restrictions,option=nolink){ } ** 制限事項と次にすること (Restrictions and things to come) Package objects as currently implemented have some restrictions. First, you cannot define or inherit overloaded methods in package objects. Second, you cannot define or inherit a member in a package object which is also the name of a top-level class or object in same package. 現在実装されているパッケージオブジェクトには、いくつかの制限があります。第一に、パッケージオブジェクト中のオーバーロードされたメソッドを定義、あるいは継承できません。第二に、同じパッケージ中でトップレベルのクラスまたはオブジェクトの名前にもなる、パッケージオブジェクト中のメンバーを定義あるいは継承できません。我々は近い将来の Scala リリースで、これらの制限がなくなることを期待しています。 興味深い問題は、パッケージ中のトップレベルのクラスまたはオブジェクトの名前が、関連するパッケージオブジェクト中で再定義されたとき何が起きるかです。当面、これは単に禁じられています。 But if we wanted to allow this, it would make sense to take the definition in the package_object as the public interface of the definition in the package itself. しかしもしこれを許したいなら、パッケージオブジェクト中の定義をパッケージそれ自身の定義の公開インターフェースとみなすことは理にかなっているでしょう。パッケージ内のコードからは、完全な定義を見ることができます。しかしパッケージ外のコードからは、パッケージオブジェクト中で何が定義されているかが見えるだけです。このようにパッケージオブジェクトは、インターフェースと実装を柔軟に組み合わせることを可能にする、かなり先進的なモジュールシステムのバックボーンに発展し得ます。 もちろん、まだすべきことはあり、詳細を練らねばなりません。しかしこれは興味深い可能性を切り開きます。 #center(){==========================================} &aname(contents,option=nolink){ } ** 目次 (Contents) - &link_anchor(where){パッケージオブジェクトをどこに入れるか} - &link_anchor(packageobj){Scala パッケージオブジェクト} - &link_anchor(restrictions){制限事項と次にすること} - &link_anchor(contents){目次} - &link_anchor(navigation){ナビゲーション} #center(){==========================================} &aname(navigation,option=nolink){ } ** ナビゲーション (Navigation) - &link_anchor(where){パッケージオブジェクトをどこに入れるか} - &link_anchor(packageobj){Scala パッケージオブジェクト} - &link_anchor(restrictions){制限事項と次にすること} - &link_anchor(contents){目次} - &link_anchor(navigation){ナビゲーション}

表示オプション

横に並べて表示:
変化行の前後のみ表示:
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。