Example7.1

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

Example7.1 - (2011/02/24 (木) 08:39:21) の1つ前との変更点

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

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

#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 } ** 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
#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 もご覧ください。