探索Scala(4)--Case Classes
5562 ワード
本文は簡単にScala言語Case Classの実現メカニズムを検討する
Case Class
Case ClassはScala言語モードマッチング機能の基礎である.クラスを定義するときにcaseキーを付けると、Case Classになります.たとえば、次のような簡単なクラスCCです.
caseキーワードはクラスにとって、いったい何を意味しているのでしょうか.以下、詳細に説明する.
単一オブジェクト
CCをコンパイルすると、2つのclass:CCが生成されます.classとCC$class.これは、Scalaがcaseクラスに単一のオブジェクトを自動的に追加することを示します.以下は逆コンパイルCC$である.classの後のコード:
apply()とunapply()メソッド
CC$はapply()メソッドを定義し、newキーワードを叩くのではなく、次のような方法でCCインスタンスを作成することができます.
unapply()CCを1つに分解します
Option.apply()およびunapply()メソッドのコードは、次のようになります.
Case ClassデフォルトはImmutable
Caseクラスのフィールドは、デフォルトでコンパイラにvalキーが付けられます.つまり、CCクラスは実際には次のようになります.
toString()、hashCode()およびequals()メソッド
Scalaコンパイラは(フィールドに基づいて)CaseクラスにtoString()、hashCode()およびequals()メソッドを書き換える責任を負います.
copy()メソッド
copy()メソッドは、Caseクラスインスタンスを完全に、または少量の変化を持って自分をコピーすることができます.次のコードに示します.
ProductとSerializableインタフェースの実装
Caseクラスはscalaも実現した.Productとscala.Serializableインタフェース(ProductとSerializableは実際にはTraits).
完全な逆コンパイルコード
以下はCC.classとCC$classの完全なコードです.参考までに:
参考資料
<>第2版
Case Class
Case ClassはScala言語モードマッチング機能の基礎である.クラスを定義するときにcaseキーを付けると、Case Classになります.たとえば、次のような簡単なクラスCCです.
case class CC(x: Int, y: Int)
それに加えてcaseキーワードはクラスにとって、いったい何を意味しているのでしょうか.以下、詳細に説明する.
単一オブジェクト
CCをコンパイルすると、2つのclass:CCが生成されます.classとCC$class.これは、Scalaがcaseクラスに単一のオブジェクトを自動的に追加することを示します.以下は逆コンパイルCC$である.classの後のコード:
public final class CC$ extends scala.runtime.AbstractFunction2 implements scala.Serializable {
public static final CC$ MODULE$;
static {
new CC$();
}
private CC$() {
MODULE$ = this;
}
public Object readResolve() {
return MODULE$;
}
...
}
apply()とunapply()メソッド
CC$はapply()メソッドを定義し、newキーワードを叩くのではなく、次のような方法でCCインスタンスを作成することができます.
val cc = CC(2, 16)
CC$は、apply()と相補的な方法も定義しています.unapply()CCを1つに分解します
Option
public final class CC$ ... {
...
public CC apply(int x, int y) {
return new CC(x, y);
}
public scala.Option<scala.Tuple2<Object, Object>> unapply(CC cc) {
if (cc == null) {
return scala.None$.MODULE$;
}
return new scala.Some(new scala.Tuple2$mcll$sp(cc.x, cc.y))
}
}
Case ClassデフォルトはImmutable
Caseクラスのフィールドは、デフォルトでコンパイラにvalキーが付けられます.つまり、CCクラスは実際には次のようになります.
case class CC(val x: Int, val y: Int)
の下はCCである.class逆コンパイル後の対応するコード:public class CC implements scala.Product, scala.Serializable {
private final int x;
private final int y;
public CC(int x, int y) {
this.x = x;
this.y = y;
scala.Product$class.$init$(this);
}
public int x() {
return x;
}
public int y() {
return y;
}
}
toString()、hashCode()およびequals()メソッド
Scalaコンパイラは(フィールドに基づいて)CaseクラスにtoString()、hashCode()およびequals()メソッドを書き換える責任を負います.
copy()メソッド
copy()メソッドは、Caseクラスインスタンスを完全に、または少量の変化を持って自分をコピーすることができます.次のコードに示します.
val cc = CC(1, 2)
val cc1 = cc.copy()
val cc2 = cc.copy(y = 8) // Named arguments
上のコードは文法糖を取り除いた後、実際には次のようになります.val cc = CC(1, 2)
val cc1 = cc.copy(cc.copy$default$1(), cc.copy$default$2())
val cc2 = cc.copy(cc.copy$default$1(), 8)
は、逆コンパイル後のcopy()およびcopy$default$n()メソッドコードです.public class CC ... {
...
public CC copy(int x, int y) {
return new CC(x, y);
}
public int copy$default$1() {
return x();
}
public int copy$default$2() {
return y();
}
...
}
ProductとSerializableインタフェースの実装
Caseクラスはscalaも実現した.Productとscala.Serializableインタフェース(ProductとSerializableは実際にはTraits).
完全な逆コンパイルコード
以下はCC.classとCC$classの完全なコードです.参考までに:
public class CC implements scala.Product, scala.Serializable {
private final int x;
private final int y;
public CC(int x, int y) {
this.x = x;
this.y = y;
scala.Product$class.$init$(this);
}
public int x() {
return x;
}
public int y() {
return y;
}
public int hashCode() {...}
public boolean equals(Object) {...}
public String toString() {...}
public boolean canEqual(Object obj) {
return obj instanceof CC;
}
public CC copy(int x, int y) {
return new CC(x, y);
}
public int copy$default$1() {
return x();
}
public int copy$default$2() {
return y();
}
// Product
// def productArity: Int
// def productElement(n: Int): Any
// def productIterator: Iterator[Any]
// def productPrefix = ""
public int productArity() {
return 2;
}
public Object productElement(int n) {
switch (n) {
case 0: return x();
case 1: return y();
default: throw new IndexOutOfBoundsException();
}
}
public scala.collection.Iterator productIterator() {
return scala.runtime.ScalaRunTime$.MODULE$.typedProductIterator(this);
}
public String productPrefix() {
return "CC";
}
public static CC apply(int x, int y) {
return CC$.MODULE$.apply(x, y);
}
public static scals.Option<scala.Tuple2<Object, Object>> unapply(CC cc) {
return CC$.MODULE$.unapply(cc);
}
public scala.Function1 static tupled() {
return CC$.MODULE$.tupled();
}
public scala.Function1 static curried() {
return CC$.MODULE$.curried();
}
}
public final class CC$ extends scala.runtime.AbstractFunction2 implements scala.Serializable {
public static final CC$ MODULE$;
static {
new CC$();
}
private CC$() {
MODULE$ = this;
}
public Object readResolve() {
return MODULE$;
}
public String toString() {
return "CC";
}
public CC apply(int x, int y) {
return new CC(x, y);
}
public scala.Option<scala.Tuple2<Object, Object>> unapply(CC cc) {
if (cc == null) {
return scala.None$.MODULE$;
}
return new scala.Some(new scala.Tuple2$mcll$sp(cc.x, cc.y))
}
}
参考資料
<