Techniquement, il n'y a pas de différence entre une classe et une classe de cas, même si le compilateur ne optimiser certaines choses lors de l'utilisation de classes de cas. Cependant, un cas de classe est utilisé pour faire disparaître la plaque de la chaudière pour un modèle spécifique, qui est la mise en œuvre des types de données algébriques.
Un exemple très simple de ces types sont des arbres. Un arbre binaire, par exemple, peut être mis en œuvre comme ceci:
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
Qui nous permettent d'effectuer les opérations suivantes:
// 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 =>
}
Notez que les arbres à construire et à déconstruire (par motif) avec la même syntaxe, qui est aussi exactement comment ils sont imprimées (sans les espaces).
Et ils peuvent également être utilisés avec pommes de cartes ou de jeux, car ils ont un valide, stable hashCode.