Quelle est la différence entre la classe de cas de Scala et la classe?
j'ai cherché dans Google pour trouver les différences entre un case class
et un class
. Tout le monde mentionne que lorsque vous voulez faire l'appariement des motifs dans la classe, utilisez la classe cas. Dans les autres cas, utilisez les classes et mentionnez aussi certains avantages supplémentaires comme les égaux et le code de hachage. Mais est-ce la seule raison pour laquelle on devrait utiliser une classe de cas au lieu de classe?
je suppose qu'il devrait y avoir une raison très importante pour cette caractéristique dans Scala. Qu'est-ce que l' explication ou est-il une ressource pour en savoir plus sur la Scala cas des classes à partir de?
14 réponses
peuvent être considérées comme des objets simples et immuables contenant des données qui devraient dépendre exclusivement de leurs arguments de constructeur .
ce concept fonctionnel nous permet de
- utiliser une syntaxe d'initialisation compacte (
Node(1, Leaf(2), None))
) - les décomposent en utilisant l'appariement des motifs
- ont des comparaisons d'égalité implicitement définies
en combinaison avec l'héritage, les classes de cas sont utilisées pour imiter types de données algébriques .
si un objet effectue des calculs statiques à l'intérieur ou présente d'autres types de comportement complexe, il doit s'agir d'une classe ordinaire.
techniquement, il n'y a pas de différence entre une classe et une classe de cas, même si le compilateur optimise certaines choses en utilisant des classes de cas. Cependant, une classe de cas est utilisée pour supprimer la plaque chauffante pour un motif spécifique, qui met en œuvre types de données algébriques .
un exemple très simple de tels types sont les arbres. Un arbre binaire, par exemple, peut être implémenté 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 permettent à nous de faire ce qui suit:
// 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 =>
}
noter que les arbres construisent et déconstruisent (par le biais de pattern match) avec la même syntaxe, qui est aussi exactement comment ils sont imprimés (moins les espaces).
et ils peuvent aussi être utilisés avec des cartes ou des ensembles de hachage, car ils ont un hashCode valide et stable.
- les classes de cas peuvent être appariées selon le modèle
- les classes de cas définissent automatiquement le hashcode et égalent Les classes de cas
- définissent automatiquement les méthodes getter pour les arguments du constructeur.
(vous avez déjà mentionné tout sauf le dernier).
ce sont les seules différences par rapport aux classes régulières.
personne n'a mentionné que les classes de cas sont aussi des instances de Product
et héritent donc de ces méthodes:
def productElement(n: Int): Any
def productArity: Int
def productIterator: Iterator[Any]
où le productArity
renvoie le nombre de paramètres de classe, productElement(i)
renvoie le i TH paramètre, et productIterator
permet itération à travers eux.
personne n'a mentionné que les classes de cas ont val
paramètres constructeur, mais c'est aussi la valeur par défaut pour les classes régulières (qui je pense est une incohérence dans la conception de Scala). Dario a laissé entendre qu'il s'agissait de immuable ".
notez que vous pouvez outrepasser la valeur par défaut en préparant l'argument de chaque constructeur avec var
pour les classes de cas. Toutefois, rendre les catégories de cas modifiables fait de leurs méthodes equals
et hashCode
une variante temporelle.[1]
sepp2k déjà mentionné que les classes de cas génèrent automatiquement les méthodes equals
et hashCode
.
en outre, personne n'a mentionné que les classes de cas créent automatiquement un compagnon object
avec le même nom que la classe, qui contient les méthodes apply
et unapply
. La méthode apply
permet de construire instances sans préparation avec new
. La méthode d'extraction unapply
permet l'appariement des motifs que d'autres ont mentionné.
le compilateur optimise également la vitesse de match
- case
correspondance des motifs pour les classes de Cas[2].
la construction de la classe de cas dans Scala peut également être considérée comme une commodité pour enlever une quelconque plaque de chaudronnier.
lors de la construction d'une classe de cas Scala vous donne ce qui suit.
- Il crée une classe ainsi que son compagnon, l'objet
- son objet compagnon met en œuvre la méthode
apply
que vous pouvez utiliser comme une méthode d'usine. Vous obtenez l'avantage de sucre syntaxique de ne pas avoir à utiliser le nouveau mot clé.
parce que la classe est immuable vous obtenez des accesseurs, qui sont juste les variables (ou propriétés) de la classe mais pas de mutateurs (donc pas de capacité à changer les variables). Les paramètres du constructeur sont automatiquement disponibles en tant que champs publics en lecture seule. Beaucoup plus agréable à utiliser que Java bean construire.
- vous obtenez aussi
hashCode
,equals
, ettoString
méthodes par défaut et la méthodeequals
compare la structure d'un objet. Une méthodecopy
est générée pour pouvoir cloner un objet.
le plus grand avantage comme cela a été mentionné précédemment est le fait que vous pouvez associer des motifs sur les classes de cas. La raison en est que vous obtenez la méthode unapply
qui vous permet de déconstruire une classe de cas pour extraire ses champs.
essentiellement ce que vous obtenez de Scala lors de la création d'une classe de cas (ou un objet de cas si votre classe ne prend pas d'arguments) est un objet simple qui sert le but comme une usine et comme un extracteur .
, Selon Scala documentation :
des classes de Cas sont juste des classes régulières que sont:
- immuable par défaut
- Décomposable par le biais de pattern matching
- comparé par égalité structurelle au lieu de par référence
- Succinct d'instancier et d'exploiter sur
une autre caractéristique du mot-clé case est que le compilateur génère automatiquement plusieurs méthodes pour nous, y compris les méthodes familières toString, equals, et hashCode en Java.
Classe:
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
^
mais si nous utilisons le même code mais utiliser la classe de cas:
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
catégorie de personnes:
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)
Pattern Matching:
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
objet: singleton:
scala> case class Person(first :String,last:String,age:Int)
defined class Person
scala> object Fred extends Person("Fred","Jones",22)
defined object Fred
personne n'a mentionné que l'objet compagnon de classe de cas a tupled
defention, qui a un type:
case class Person(name: String, age: Int)
//Person.tupled is def tupled: ((String, Int)) => Person
le seul cas d'utilisation que je peux trouver est quand vous avez besoin de construire la classe de cas de tuple, exemple:
val bobAsTuple = ("bob", 14)
val bob = (Person.apply _).tupled(bobAsTuple) //bob: Person = Person(bob,14)
vous pouvez faire la même chose, sans tupled, en créant l'objet directement, mais si vos ensembles de données exprimés en liste de tuple avec arity 20(tuple avec 20 éléments), peut être en utilisant tupled est votre choix.
Un classe de cas de est une classe qui peut être utilisé avec le match/case
.
def isIdentityFun(term: Term): Boolean = term match {
case Fun(x, Var(y)) if x == y => true
case _ => false
}
vous voyez que case
est suivi d'une instance de classe Fun dont le 2e paramètre est un Var. C'est une syntaxe très agréable et puissante, mais elle ne peut pas fonctionner avec les instances d'une classe, donc il y a des restrictions pour les classes de cas. Et si ces restrictions sont respectées, il est possible de définir automatiquement hashcode et equals.
l'expression vague" un mécanisme récursif de décomposition par appariement de motifs "signifie simplement "cela fonctionne avec case
". (En effet, L'instance suivie par match
est comparée à (comparée à) l'instance qui suit case
, Scala doit les décomposer tous les deux, et doit décomposer récursivement de quoi ils sont faits.)
à quoi servent les classes de cas ? L'article Wikipédia sur L'algébrique Les types de données donnent deux bons exemples classiques, des listes et des arbres. La prise en charge des types de données algébriques (y compris savoir les comparer) est un must pour tout langage fonctionnel moderne.
quelles classes de cas sont et non utiles pour? Certains objets ont l'état, le code comme connection.setConnectTimeout(connectTimeout)
n'est pas pour les classes de cas.
et maintenant vous pouvez lire un Tour de Scala: cas Classes
outre ce que les gens ont déjà dit, il y a quelques différences plus fondamentales entre class
et case class
1. Case Class
n'a pas besoin de new
explicite, alors que la classe doit être appelée avec new
val classInst = new MyClass(...) // For classes
val classInst = MyClass(..) // For case class
2.By les paramètres par défaut des constructeurs sont privés dans class
, tandis que son public dans case class
// For class
class MyClass(x:Int) { }
val classInst = new MyClass(10)
classInst.x // FAILURE : can't access
// For caseClass
case class MyClass(x:Int) { }
val classInst = MyClass(10)
classInst.x // SUCCESS
3. case class
se comparent par valeur 1519120920"
// case Class
class MyClass(x:Int) { }
val classInst = new MyClass(10)
val classInst2 = new MyClass(10)
classInst == classInst2 // FALSE
// For Case Class
case class MyClass(x:Int) { }
val classInst = MyClass(10)
val classInst2 = MyClass(10)
classInst == classInst2 // TRUE
Contrairement aux classes, les classes de cas ne sont utilisées que pour contenir des données.
les classes de cas sont flexibles pour les applications centrées sur les données, ce qui signifie que vous pouvez définir les champs de données dans la classe de cas et définir la logique commerciale dans un objet compagnon. De cette façon, vous séparez les données de la logique commerciale.
avec la méthode de Copie, vous pouvez hériter n'importe quelle ou toutes les propriétés requises de la source et pouvez les changer comme vous voulez.
- classes de définir un compagnon de l'objet à appliquer et à annuler les méthodes
- des classes de Cas extends Serializable
- classes de cas define égale hashCode et méthodes de copie
- Tous les attributs de l'constructeur val (sucre syntaxique)
je pense que dans l'ensemble, toutes les réponses ont donné une explication sémantique au sujet des classes et des classes de cas. Cela pourrait être très pertinent, mais chaque internaute novice à scala devrait savoir ce qui se passe quand vous créez une classe de cas. J'ai écrit cette réponse , qui explique la classe de cas en un mot.
chaque programmeur devrait savoir que s'ils utilisent des fonctions pré-construites, alors ils écrivent un code comparativement moins, ce qui leur permet en donnant le pouvoir d'écrire le code le plus optimisé, mais le pouvoir vient avec de grandes responsabilités. Ainsi, utilisez des fonctions prébuilt avec des précautions très.
certains développeurs évitent d'écrire des classes de cas en raison de 20 méthodes supplémentaires, que vous pouvez voir en démontant le fichier de classe.
s'il vous Plaît consultez ce lien si vous voulez vérifier toutes les méthodes à l'intérieur d'une classe de cas de .