Example7.1

「Example7.1」の編集履歴(バックアップ)一覧はこちら

Example7.1 - (2008/05/09 (金) 01:14:36) の最新版との変更点

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

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

** 7.1 Case Classes and Case Objects Case classes and case objects are defined like a normal classes or objects, except that the definition is prefixed with the modifier case. For instance, the definitions 「ケースクラス」と「ケースオブジェクト」は普通のクラスやオブジェクトのように定義されますが、定義に修飾子 case が前に付く事がだけが違います。例えば定義 abstract class Expr case class Number(n: Int) extends Expr case class Sum(e1: Expr, e2: Expr) extends Expr introduce Number and Sum as case classes. The case modifier in front of a class or object definition has the following effects. は Number と Sum をケースクラスとして導入します。クラスやオブジェクト定義の前の case 修飾子は次の様な効果があります。 1. Case classes implicitly come with a constructor function, with the same name as the class. In our example, the two functions 1. ケースクラスは暗黙的にコンストラクタ関数を伴い、それはクラスと同じ名前です。我々の例の場合、二つの関数 def Number(n: Int) = new Number(n) def Sum(e1: Expr, e2: Expr) = new Sum(e1, e2) would be added. Hence, one can now construct expression trees a bit more concisely, as in が追加されます。従って式の木をもう少し簡潔に次の様に構成出来ます。 Sum(Sum(Number(1), Number(2)), Number(3)) 2. Case classes and case objects implicitly come with implementations of methods toString, equals and hashCode, which override the methods with the same name in class AnyRef. The implementation of these methods takes in each case the structure of a member of a case class into account. The toString method represents an expression tree the way it was constructed. So, 2. ケースクラスとケースオブジェクトは暗黙的にメソッド toString, equals, hashCode を伴い、それらはクラス AnyRef の同名のメソッドをオーバライドします。これらのメソッドの実装はそれぞれのケースでケースクラスの構造を考慮しています。toString メソッドは式の木が構成された方法を表します。従って Sum(Sum(Number(1), Number(2)), Number(3)) would be converted to exactly that string, whereas the default implementation in class AnyRef would return a string consisting of the outermost constructor name Sum and a number. The equals methods treats two case members of a case class as equal if they have been constructed with the same constructor and with arguments which are themselves pairwise equal. This also affects the implementation of == and !=, which are implemented in terms of equals in Scala. So, はその文字列そのままに変換されます。一方、クラス AnyRef のデフォルトの実装は一番外側のコンストラクタの名前 Sum と数字からなる文字列を返すでしょう。equals メソッドはケースクラスの二つのケースメンバを、もし同じコンストラクタで構築されかつそれらの引数がそれぞれ等しいならば、等しいと扱います。これは == と != の実装にも影響しますが、それらは Scala では equals を用いて実装されているからです。従って Sum(Number(1), Number(2)) == Sum(Number(1), Number(2)) will yield true. If Sum or Number were not case classes, the same expression would be false, since the standard implementation of equals in class AnyRef always treats objects created by different constructor calls as being different. The hashCode method follows the same principle as other two methods. It computes a hash code from the case class constructor name and the hash codes of the constructor arguments, instead of from the object’s address, which is what the as the default implementation of hashCode does. は true を返します。もし Sum や Number がケースクラスでないならば、同じ式は false を返しますが、それはクラス AnyRef の equals の標準の実装では異なったコンストラクタ呼び出しで生成されたオブジェクトは常に異なると扱うからです。hashCode メソッドも他の二つのメソッドと同様の原則に従います。デフォルトの hashCode の実装が行うオブジェクトのアドレスからの計算の代わりに、ハッシュコードをケースクラスのコンストラクタ名とコンストラクタ引数のハッシュコードから計算します。 3. Case classes implicitly come with nullary accessor methods which retrieve the constructor arguments. In our example, Number would obtain an accessor method 3. ケースクラスは暗黙的にコンストラクタ引数を取り出す引数無しアクセサメソッドを伴います。我々の例では、Number はアクセサメソッド def n: Int which returns the constructor parameter n, whereas Sum would obtain two accessor methods を持ち、コンストラクタ仮引数 n を返します。一方 Sum は二つのアクセサメソッドを持ちます。 def e1: Expr, e2: Expr Hence, if for a value s of type Sum, say, one can now write s.e1, to access the left operand. However, for a value e of type Expr, the term e.e1 would be illegal since e1 is defined in Sum; it is not a member of the base class Expr. So, how do we determine the constructor and access constructor arguments for values whose static type is the base class Expr? This is solved by the fourth and final particularity of case classes. 従って、例えば型 Sum の値 s に対して、左オペランドにアクセスする為に s.e1 と書く事が出来ます。しかし、型 Expr の値 e に対して項 e.e1 は正しくありませんが、それは e1 は Sum で定義されているのであって基底クラス Expr のメンバではないからです。では、静的型が基底クラス Expr である値に対してどうやってコンストラクタを判別してコンストラクタ引数にアクセスすれば良いのでしょうか?。これはケースクラスの四番目にして最後の特徴によって解決されます。 4. Case classes allow the constructions of patterns which refer to the case class constructor. 4. ケースクラスではケースクラスのコンストラクタを参照する「パターン」の構築が可能です。 ---- #comment
#co(){ 7.1 Case Classes and Case Objects Case classes and case objects are defined like a normal classes or objects, except that the definition is prefixed with the modifier case. For instance, the definitions } #setmenu2(ex-r-menu) ** 7.1 ケースクラスとケースオブジェクト &bold(){ケースクラス}と&bold(){ケースオブジェクト}は普通のクラスやオブジェクトのように定義しますが、定義に修飾子 case が手前に付くことだけが違います。たとえば定義 abstract class Expr case class Number(n: Int) extends Expr case class Sum(e1: Expr, e2: Expr) extends Expr #co(){ introduce Number and Sum as case classes. The case modifier in front of a class or object definition has the following effects. } は、Number と Sum をケースクラスとして導入します。クラスやオブジェクト定義の前の case 修飾子には、次のような効果があります。 #co(){ 1. Case classes implicitly come with a constructor function, with the same name as the class. In our example, the two functions } 1. ケースクラスは暗黙のうちにコンストラクタ関数を伴い、それはクラスと同じ名前です。この例の場合、2つの関数 def Number(n: Int) = new Number(n) def Sum(e1: Expr, e2: Expr) = new Sum(e1, e2) #co(){ would be added. Hence, one can now construct expression trees a bit more concisely, as in } が追加されます。したがって式の木をもう少し簡潔に、次のように構成できます。 Sum(Sum(Number(1), Number(2)), Number(3)) #co(){ 2. Case classes and case objects implicitly come with implementations of methods toString, equals and hashCode, which override the methods with the same name in class AnyRef. The implementation of these methods takes in each case the structure of a member of a case class into account. The toString method represents an expression tree the way it was constructed. So, } 2. ケースクラスとケースオブジェクトは暗黙のうちにメソッド toString、equals、hashCode を伴い、それらはクラス AnyRef の同名のメソッドをオーバーライドします。これらのメソッド実装では、それぞれのケースクラスのメンバ構造を考慮しています。toString メソッドは式の木が構成された方法を表します。したがって、 Sum(Sum(Number(1), Number(2)), Number(3)) #co(){ would be converted to exactly that string, whereas the default implementation in class AnyRef would return a string consisting of the outermost constructor name Sum and a number. The equals methods treats two case members of a case class as equal if they have been constructed with the same constructor and with arguments which are themselves pairwise equal. This also affects the implementation of == and !=, which are implemented in terms of equals in Scala. So, } は、この文字列そのままに変換されます。一方、クラス AnyRef のデフォルトの実装は、一番外側のコンストラクタの名前 Sum と数字からなる文字列を返すでしょう。equals メソッドはケースクラスの2つのケースメンバを、もし同じコンストラクタで構築され、かつ、それらの引数がそれぞれ等しいなら、等しいと扱います。これは == と != の実装にも影響しますが、それらは Scala では equals を用いて実装されているからです。したがって Sum(Number(1), Number(2)) == Sum(Number(1), Number(2)) #co(){ will yield true. If Sum or Number were not case classes, the same expression would be false, since the standard implementation of equals in class AnyRef always treats objects created by different constructor calls as being different. The hashCode method follows the same principle as other two methods. It computes a hash code from the case class constructor name and the hash codes of the constructor arguments, instead of from the object's address, which is what the as the default implementation of hashCode does. } は、true を返します。もし Sum や Number がケースクラスでないなら、同じ式は false を返します。なぜならクラス AnyRef の equals の標準実装では、異なるコンストラクタ呼び出しで生成されたオブジェクトは常に異なる、と扱うからです。hashCode メソッドも他の2つのメソッドと同じ原則に従います。デフォルトの hashCode の実装ではハッシュコードを、オブジェクトのアドレスから計算する代わりに、ケースクラスのコンストラクタ名と、コンストラクタ引数のハッシュコードから計算します。 #co(){ 3. Case classes implicitly come with nullary accessor methods which retrieve the constructor arguments. In our example, Number would obtain an accessor method } 3. ケースクラスは暗黙のうちに、パラメータなしのアクセサメソッドを伴い、それはコンストラクタ引数を読み出します。例では、Number はアクセサメソッド def n: Int #co(){ which returns the constructor parameter n, whereas Sum would obtain two accessor methods } を持ち、コンストラクタパラメータ n を返します。一方 Sum は2つのアクセサメソッドを持ちます。 def e1: Expr, e2: Expr #co(){ Hence, if for a value s of type Sum, say, one can now write s.e1, to access the left operand. However, for a value e of type Expr, the term e.e1 would be illegal since e1 is defined in Sum; it is not a member of the base class Expr. So, how do we determine the constructor and access constructor arguments for values whose static type is the base class Expr? This is solved by the fourth and final particularity of case classes. } したがって、たとえば型 Sum の値 s に対して、左オペランドにアクセスするために s.e1 と書けます。しかし、型 Expr の値 e に対して項 e.e1 は正しくありませんが、それは e1 は Sum で定義されているのであって基底クラス Expr のメンバではないからです。では、静的型が基底クラス Expr である値に対してどうやってコンストラクタを判別してコンストラクタ引数にアクセスすれば良いのでしょうか? これはケースクラスの四番目にして最後の特徴によって解決されます。 #co(){ 4. Case classes allow the constructions of patterns which refer to the case class constructor. } 4. ケースクラスを使えば、ケースクラスのコンストラクタを参照する&bold(){パターン}を構築できます。 #center(){[[前ページ>ExampleChap7]] [[ 7 章>ExampleChap7]] [[目次>ScalaByExample和訳]] [[次ページ>Example7.2]]} ---- #comment

表示オプション

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

下から選んでください:

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