3
  {
      class MyClass(name: String) {} 
      val x = new MyClass("x")
      println(x.name)         // Error name is not a member of MyClass
  }

しかし

  {
      abstract class Base

      case class MyClass(name: String) extends Base {}

      var x = new MyClass("x")
      println(x.name)           // name is a member of MyClass
  }

では、ケース クラスはどうなるでしょうか。すべてのコンストラクタ パラメータが変数に変換されるのはなぜですか。

4

4 に答える 4

2

nameは両方の例でメンバーですが、最初の例ではプライベートですが、2 番目の例ではパブリックです。ケース クラスは、public valデフォルトでコンストラクタ パラメータを作成します。

于 2013-08-12T18:46:42.420 に答える
2

パターン マッチングは最も重要ですが、ケース クラスの唯一のアプリケーションではありません。もう 1 つの重要な点は、コンストラクターの引数 (別名 product 要素) に関してメソッドequalsとメソッドを実装することです。hashCodeしたがって、ケース クラスは、セット内の要素またはマップ内のキーとして機能するデータ構造を定義するのに非常に役立ちます。これは、これらの要素が表示されている場合にのみ意味があります。

比較:

class Foo(val i: Int)

val set1 = Set(new Foo(33))
set1.contains(new Foo(33))  // false!!

と:

case class Bar(val i: Int)

val set2 = Set(Bar(33)
set2.contains(Bar(33))      // true!

パラメータが等しい 2 つのケース クラス インスタンスは、それ自体が等しい。それらがいくつかの「定数」を表していると想像できます。これは、変更可能な状態を保持してはならないことを意味します。

ただし、2 番目のパラメーター リストを使用して、等式から引数を除外することができます。

case class Baz(i: Int)(val n: Long)

Baz(33)(5L) == Baz(33)(6L)  // true!

コンストラクターの引数が値になることを意味するもう 1 つの便利な機能は、コピーの作成です。これが不変データの変更方法です。特定の値を変更して新しいインスタンスを作成し、元の値はそのままにします。

case class Person(name: String, age: Int)

val p1 = Person("Fuzzi", 33)
val p2 = p1.copy(age = 34)

copy メソッドは、指定されていないすべての引数にデフォルト値を使用し、それらの値をコンストラクター引数から取得します。

于 2013-08-12T19:15:23.553 に答える
2

明確にするために、コンストラクターの引数は変数を作成するために使用されるのではなく、値を作成するために使用されます。

最初の例で指定valした場合、非ケース クラス:

class MyClass(val name: String) {} 

次に、ケース クラスの場合と同じように、パブリック値に変換された引数も取得します。

Scala-Lang サイトの例では、次のように書かれています。

パターン マッチングを使用してデータ構造を分解する場合にのみ、ケース クラスを定義する意味があります。次のオブジェクトは、ラムダ計算表現のプリティ プリンター関数を定義します。

次にコード例を示します。

object TermTest extends Application {   def printTerm(term: Term) {
    term match {
      case Var(n) =>
        print(n)
      case Fun(x, b) =>
        print("^" + x + ".")
        printTerm(b)
      case App(f, v) =>
        Console.print("(")
        printTerm(f)
        print(" ")
        printTerm(v)
        print(")")
    }   }   def isIdentityFun(term: Term): Boolean = term match {
    case Fun(x, Var(y)) if x == y => true
    case _ => false   }   val id = Fun("x", Var("x"))   val t = Fun("x", Fun("y", App(Var("x"), Var("y"))))   printTerm(t)   println   println(isIdentityFun(id))   println(isIdentityFun(t)) }
于 2013-08-12T18:48:21.427 に答える
1

利用可能なスペースが不足しているためにコメントに何かを追加するには、次のケース クラスの例を検討してください。

case class My(x: Int)

ファイルに保存して に渡すとscalac -print、次の拡張コードが得られます (重要でないものを削除しました)。

case class My extends Object with Product with Serializable {
<caseaccessor> <paramaccessor> private[this] val x: Int = _; 
<stable> <caseaccessor> <accessor> <paramaccessor> def x(): Int = My.this.x;

ここで注意<caseaccessor>してください。

次に、コンパニオン オブジェクト:

      <synthetic> object My extends runtime.AbstractFunction1 with Serializable {
        case <synthetic> def apply(x: Int): My = new My(x);
        case <synthetic> def unapply(x$0: My): Option = if (x$0.==(null))
          scala.this.None
        else
          new Some(scala.Int.box(x$0.x()));
        case <synthetic> <bridge> def apply(v1: Object): Object = My.this.apply(scala.Int.unbox(v1));
//...

お知らせapplyunapplyこちら。自分で完全な出力を見ると、scala がコードを生成する方法について詳しく知ることができます。

于 2013-08-12T19:10:00.743 に答える