494 Stimmen

Was ist der Unterschied zwischen Scalas Fallklasse und Klasse?

Ich suchte in Google nach den Unterschieden zwischen einer case class und eine class . Jeder erwähnt, dass, wenn Sie Musterabgleich auf die Klasse tun wollen, verwenden Sie Fallklasse. Andernfalls verwenden Sie Klassen und auch die Erwähnung einige zusätzliche Vorteile wie Gleichheit und Hash-Code überschreiben. Aber sind dies die einzigen Gründe, warum man eine Fallklasse anstelle einer Klasse verwenden sollte?

Ich vermute, dass es einen sehr wichtigen Grund für diese Funktion in Scala geben muss. Was ist die Erklärung oder gibt es eine Ressource, um mehr über die Scala Fallklassen zu lernen?

448voto

Dario Punkte 47246

Fallklassen können wie folgt betrachtet werden einfache und unveränderliche datenhaltende Objekte, die ausschließlich von ihren Konstruktorargumenten abhängen sollten .

Dieses funktionale Konzept ermöglicht es uns

  • verwenden eine kompakte Initialisierungssyntax ( Node(1, Leaf(2), None)) )
  • sie mit Hilfe von Mustervergleichen zerlegen
  • haben Gleichheitsvergleiche implizit definiert

In Kombination mit der Vererbung werden Fallklassen zur Nachahmung von algebraische Datentypen .

Wenn ein Objekt im Inneren zustandsabhängige Berechnungen durchführt oder andere Arten von komplexem Verhalten zeigt, sollte es eine gewöhnliche Klasse sein.

174voto

Daniel C. Sobral Punkte 290004

Technisch gesehen gibt es keinen Unterschied zwischen einer Klasse und einer Fallklasse - auch wenn der Compiler einige Dinge bei der Verwendung von Fallklassen optimiert. Eine Fallklasse wird jedoch verwendet, um eine Kesselplatte für ein bestimmtes Muster zu beseitigen, nämlich die Implementierung algebraische Datentypen .

Ein sehr einfaches Beispiel für solche Typen sind Bäume. Ein binärer Baum kann zum Beispiel wie folgt implementiert werden:

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

Damit können wir Folgendes tun:

// 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 =>
}

Beachten Sie, dass Bäume mit der gleichen Syntax konstruiert und dekonstruiert werden (durch Musterübereinstimmung), und dass dies auch genau die Art ist, wie sie gedruckt werden (ohne Leerzeichen).

Und sie können auch mit Hash-Maps oder Sets verwendet werden, da sie einen gültigen, stabilen HashCode haben.

79voto

sepp2k Punkte 352762
  • Fallklassen können mit Mustern abgeglichen werden
  • Fallklassen definieren automatisch Hashcode und Gleichheitszeichen
  • Case-Klassen definieren automatisch Getter-Methoden für die Konstruktorargumente.

(Sie haben bereits alle bis auf den letzten erwähnt).

Das sind die einzigen Unterschiede zum regulären Unterricht.

32voto

Shelby Moore III Punkte 5909

Niemand hat erwähnt, dass Fallklassen val Konstruktorparameter, doch ist dies auch der Standard für reguläre Klassen (die Ich halte das für eine Ungereimtheit bei der Entwicklung von Scala). Dario deutete dies an, als er feststellte, dass sie " unveränderlich ".

Beachten Sie, dass Sie den Standard überschreiben können, indem Sie dem jeweiligen Konstruktorargument ein var für Fallklassen. Wenn Fallklassen jedoch veränderbar sind, führt das dazu, dass ihre equals y hashCode Methoden als Zeitvariante[1].

sepp2k bereits erwähnt, dass Fallklassen automatisch generieren equals y hashCode Methoden.

Außerdem hat niemand erwähnt, dass Fallklassen automatisch einen Begleiter erstellen object mit demselben Namen wie die Klasse, die Folgendes enthält apply y unapply Methoden. Die Website apply Methode ermöglicht die Erstellung von Instanzen ohne Voranstellen von new . Die unapply Extraktor-Methode ermöglicht den von anderen erwähnten Musterabgleich.

Außerdem optimiert der Compiler die Geschwindigkeit der match - case Mustervergleich für Fallklassen[2].

[1] Case Classes sind cool

[2] Gehäuseklassen und Extraktoren, S. 15 .

30voto

Jean-Philippe Pellet Punkte 57683

Niemand hat erwähnt, dass Fallklassen auch Instanzen von Product und erben somit diese Methoden:

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

wo die productArity gibt die Anzahl der Klassenparameter zurück, productElement(i) gibt die i th Parameter, und productIterator ermöglicht die Iteration durch sie.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X