474

case classaと aの違いを Google で検索しましたclass。クラスでパターンマッチングを行いたい場合は、ケースクラスを使用することを誰もが言及しています。それ以外の場合は、クラスを使用し、equals やハッシュ コードのオーバーライドなどの追加の特典についても言及します。しかし、これらがクラスの代わりにケース クラスを使用する唯一の理由でしょうか?

Scala のこの機能には、非常に重要な理由があるはずです。説明は何ですか、または Scala ケース クラスについてさらに学ぶためのリソースはありますか?

4

17 に答える 17

429

ケース クラスは、コンストラクターの引数に排他的に依存するプレーンで不変のデータ保持オブジェクトと見なすことができます。

この機能的な概念により、次のことが可能になります。

  • コンパクトな初期化構文を使用する ( Node(1, Leaf(2), None)))
  • パターンマッチングを使用してそれらを分解する
  • 暗黙的に定義された等価比較を持つ

継承と組み合わせて、ケース クラスは代数的データ型を模倣するために使用されます。

オブジェクトが内部でステートフルな計算を実行するか、他の種類の複雑な動作を示す場合、それは通常のクラスである必要があります。

于 2010-02-22T17:57:02.873 に答える
171

技術的には、クラスとケースクラスの間に違いはありません。コンパイラがケースクラスを使用するときにいくつかのものを最適化したとしてもです。ただし、ケースクラスは、代数的データ型を実装している特定のパターンのボイラープレートを廃止するために使用されます。

そのようなタイプの非常に単純な例は木です。たとえば、二分木は次のように実装できます。

sealed abstract class Tree
case class Node(left: Tree, right: Tree) extends Tree
case class Leaf[A](value: A) extends Tree
case object EmptyLeaf extends Tree

これにより、次のことが可能になります。

// DSL-like assignment:
val treeA = Node(EmptyLeaf, Leaf(5))
val treeB = Node(Node(Leaf(2), Leaf(3)), Leaf(5))

// On Scala 2.8, modification through cloning:
val treeC = treeA.copy(left = treeB.left)

// Pretty printing:
println("Tree A: "+treeA)
println("Tree B: "+treeB)
println("Tree C: "+treeC)

// Comparison:
println("Tree A == Tree B: %s" format (treeA == treeB).toString)
println("Tree B == Tree C: %s" format (treeB == treeC).toString)

// Pattern matching:
treeA match {
  case Node(EmptyLeaf, right) => println("Can be reduced to "+right)
  case Node(left, EmptyLeaf) => println("Can be reduced to "+left)
  case _ => println(treeA+" cannot be reduced")
}

// Pattern matches can be safely done, because the compiler warns about
// non-exaustive matches:
def checkTree(t: Tree) = t match {
  case Node(EmptyLeaf, Node(left, right)) =>
  // case Node(EmptyLeaf, Leaf(el)) =>
  case Node(Node(left, right), EmptyLeaf) =>
  case Node(Leaf(el), EmptyLeaf) =>
  case Node(Node(l1, r1), Node(l2, r2)) =>
  case Node(Leaf(e1), Leaf(e2)) =>
  case Node(Node(left, right), Leaf(el)) =>
  case Node(Leaf(el), Node(left, right)) =>
  // case Node(EmptyLeaf, EmptyLeaf) =>
  case Leaf(el) =>
  case EmptyLeaf =>
}

ツリーは同じ構文で構築および分解(パターンマッチを介して)することに注意してください。これは、ツリーの印刷方法(スペースを除く)でもあります。

また、有効で安定したhashCodeがあるため、ハッシュマップまたはセットで使用することもできます。

于 2010-02-23T11:47:28.847 に答える
78
  • ケースクラスはパターンマッチ可能
  • ケースクラスは自動的に hashcode と equals を定義します
  • ケース クラスは、コンストラクター引数の getter メソッドを自動的に定義します。

(あなたはすでに最後のものを除いてすべて言及しました)。

これらは、通常のクラスとの唯一の違いです。

于 2010-02-22T17:57:14.337 に答える
31

Productケースクラスがインスタンスでもあるため、これらのメソッドを継承するとは誰も言及していません。

def productElement(n: Int): Any
def productArity: Int
def productIterator: Iterator[Any]

ここで、productArityはクラス パラメータの数をproductElement(i)返し、i番目のパラメータを返し、productIteratorそれらを反復できるようにします。

于 2011-01-13T16:41:31.813 に答える
30

valケースクラスにコンストラクターパラメーターがあるとは誰も言及していませんが、これは通常のクラスのデフォルトでもあります (これは Scala の設計の矛盾だと思います)。ダリオは、それらが「不変」であると指摘したところで、そのようなことをほのめかしました。

var各コンストラクター引数の先頭にfor ケース クラスを追加することで、デフォルトをオーバーライドできることに注意してください。ただし、ケース クラスをミュータブルにすると、そのクラスequalshashCodeメソッドが時変になります。[1]

sepp2kequalsは、ケース クラスが自動的におよびhashCodeメソッドを生成することを既に述べました。

objectまた、ケース クラスがクラスと同じ名前のコンパニオンを自動的に作成し、メソッドが含まれてapplyいるunapplyことについて誰も言及していません。このapplyメソッドを使用すると、先頭に を付けずにインスタンスを構築できますnew。抽出メソッドにより、他のunapply人が言及したパターン マッチングが可能になります。

また、コンパイラは、ケース クラスのパターン マッチングの速度を最適化しmatchますcase[2]。

[1]ケースクラスはかっこいい

[2]ケース クラスとエクストラクタ、15 ページ

于 2013-09-07T05:24:43.860 に答える
18

Scala のケース クラス コンストラクトは、いくつかのボイラープレートを削除するための便利なものと見なすこともできます。

ケースクラスを構築するとき、Scala は以下を提供します。

  • クラスとそのコンパニオン オブジェクトを作成します。
  • そのコンパニオン オブジェクトはapply、ファクトリ メソッドとして使用できるメソッドを実装します。new キーワードを使用する必要がないというシンタックス シュガーの利点が得られます。

クラスは不変であるため、クラスの単なる変数 (またはプロパティ) であるアクセサーを取得しますが、ミューテーターはありません (変数を変更する機能はありません)。コンストラクターのパラメーターは、読み取り専用のパブリック フィールドとして自動的に使用できます。Java Bean コンストラクトよりもはるかに使いやすい。

  • また、デフォルトでhashCodeequals、およびメソッドを取得し、メソッドはオブジェクトを構造的に比較します。オブジェクトのクローンを作成できるようにメソッドが生成されます (いくつかのフィールドには新しい値がメソッドに提供されます) 。toStringequalscopy

前述の最大の利点は、ケース クラスでパターン マッチができることです。unapplyこれは、ケース クラスを分解してそのフィールドを抽出できるメソッドを 取得できるためです。


本質的に、ケース クラス (クラスが引数を取らない場合はケース オブジェクト) を作成するときに Scala から得られるものは、ファクトリおよびエクストラクタとしての目的を果たすシングルトン オブジェクトです。

于 2015-05-29T13:06:39.380 に答える
6

クラス:

scala> class Animal(name:String)
defined class Animal

scala> val an1 = new Animal("Padddington")
an1: Animal = Animal@748860cc

scala> an1.name
<console>:14: error: value name is not a member of Animal
       an1.name
           ^

しかし、同じコードを使用し、ケース クラスを使用する場合:

scala> case class Animal(name:String)
defined class Animal

scala> val an2 = new Animal("Paddington")
an2: Animal = Animal(Paddington)

scala> an2.name
res12: String = Paddington


scala> an2 == Animal("fred")
res14: Boolean = false

scala> an2 == Animal("Paddington")
res15: Boolean = true

人物クラス:

scala> case class Person(first:String,last:String,age:Int)
defined class Person

scala> val harry = new Person("Harry","Potter",30)
harry: Person = Person(Harry,Potter,30)

scala> harry
res16: Person = Person(Harry,Potter,30)
scala> harry.first = "Saily"
<console>:14: error: reassignment to val
       harry.first = "Saily"
                   ^
scala>val saily =  harry.copy(first="Saily")
res17: Person = Person(Saily,Potter,30)

scala> harry.copy(age = harry.age+1)
res18: Person = Person(Harry,Potter,31)

パターンマッチング:

scala> harry match {
     | case Person("Harry",_,age) => println(age)
     | case _ => println("no match")
     | }
30

scala> res17 match {
     | case Person("Harry",_,age) => println(age)
     | case _ => println("no match")
     | }
no match

オブジェクト: シングルトン:

scala> case class Person(first :String,last:String,age:Int)
defined class Person

scala> object Fred extends Person("Fred","Jones",22)
defined object Fred
于 2016-08-12T11:32:51.387 に答える
4

ケース クラスのコンパニオン オブジェクトにtupled次の型を持つ防御があるとは誰も言及していません。

case class Person(name: String, age: Int)
//Person.tupled is def tupled: ((String, Int)) => Person

私が見つけることができる唯一のユースケースは、タプルからケースクラスを構築する必要がある場合です。例:

val bobAsTuple = ("bob", 14)
val bob = (Person.apply _).tupled(bobAsTuple) //bob: Person = Person(bob,14)

オブジェクトを直接作成することで、タプルなしで同じことを行うことができますが、データセットがアリティ 20 のタプル (20 要素のタプル) のリストとして表現されている場合、タプルを使用している可能性があります。

于 2017-01-11T15:18:22.280 に答える
1

の主な機能の一部をcase classes以下に示します。

  1. ケース クラスは不変です。
  2. newキーワードなしでケース クラスをインスタンス化できます。
  3. ケースクラスは値で比較できます

scala docs から取得した、scala fiddle のサンプル scala コード。

https://scalafiddle.io/sf/34XEQyE/0

于 2019-08-29T16:28:12.887 に答える