J'essaie de comprendre la différence entre ces quatre méthodes. Je sais par défaut qui ==
appelle la méthode equal?
qui retourne vrai lorsque les deux opérandes se réfèrent exactement au même objet.
===
par défaut, appelle également ==
lequel appelle equal?
... d'accord, donc si ces trois méthodes ne sont pas remplacées, alors je suppose
===
, ==
et equal?
faites exactement la même chose?
Vient maintenant eql?
. Qu'est-ce que cela fait (par défaut)? Appelle-t-il le hachage / id de l'opérande?
Pourquoi Ruby a-t-il autant de signes d'égalité? Sont-ils censés différer en sémantique?
ruby
comparison
operators
equality
denniss
la source
la source
"a" == "a"
,"a" === "a"
et"a".eql? "a"
. Mais c'est faux:"a".equal? "a"
(Le mien est rubis 1.9.2-p180)a = Object.new; b = Object.new
alors tout==
,===
,.equal?
,.eql?
retourneratrue
poura
vsa
et faux poura
vsb
.Réponses:
Je vais citer abondamment la documentation Object ici, car je pense qu'elle a de bonnes explications. Je vous encourage à le lire, ainsi que la documentation de ces méthodes car elles sont remplacées dans d'autres classes, comme String .
Note latérale: si vous voulez les essayer par vous-même sur différents objets, utilisez quelque chose comme ceci:
==
- "égalité" génériqueC'est la comparaison la plus courante, et donc l'endroit le plus fondamental où vous (en tant qu'auteur d'une classe) pouvez décider si deux objets sont "égaux" ou non.
===
- égalité des casC'est incroyablement utile. Exemples de choses qui ont des
===
implémentations intéressantes :Vous pouvez donc faire des choses comme:
Voir ma réponse ici pour un exemple clair de la façon dont
case
+Regex
peut rendre le code beaucoup plus propre. Et bien sûr, en fournissant votre propre===
implémentation, vous pouvez obtenir unecase
sémantique personnalisée .eql?
-Hash
égalitéVous êtes donc libre de remplacer cela pour vos propres utilisations, ou vous pouvez remplacer
==
et utiliser dealias :eql? :==
sorte que les deux méthodes se comportent de la même manière.equal?
- comparaison d'identitéIl s'agit en fait d'une comparaison de pointeurs.
la source
Numeric
cela la gère d'une manière plus stricte que==
. C'est vraiment à l'auteur de la classe.===
est rarement utilisé en dehors descase
déclarations.===
comme signifiant "correspond" (grosso modo). Comme dans ", l'expression rationnelle correspond-elle à la chaîne" ou "la plage correspond-elle (inclut-elle) au nombre".J'aime la réponse jtbandes, mais comme elle est assez longue, j'ajouterai ma propre réponse compacte:
==
,===
,eql?
,equal?
Y a 4 comparateurs, ie. 4 façons de comparer 2 objets, en Ruby.
Comme, dans Ruby, tous les comparateurs (et la plupart des opérateurs) sont en fait des appels de méthode, vous pouvez modifier, remplacer et définir vous-même la sémantique de ces méthodes de comparaison. Cependant, il est important de comprendre, lorsque les constructions de langage interne de Ruby utilisent quel comparateur:
==
(comparaison de valeurs)Ruby utilise: == partout pour comparer les valeurs de 2 objets, par exemple. Valeurs de hachage:
===
(comparaison de cas)Ruby utilise: === dans les constructions case / when. Les extraits de code suivants sont logiquement identiques:
eql?
(Comparaison par clé de hachage)Ruby utilise: eql? (en combinaison avec la méthode de hachage) pour comparer les touches de hachage. Dans la plupart des cours: eql? est identique à: ==.
Connaissance de: eql? n'est important que lorsque vous souhaitez créer vos propres classes spéciales:
Remarque: L'ensemble de classe Ruby couramment utilisé repose également sur la comparaison de clé de hachage.
equal?
(comparaison d'identité d'objet)Ruby utilise: égal? pour vérifier si deux objets sont identiques. Cette méthode (de la classe BasicObject) n'est pas censée être remplacée.
la source
eql?
est très trompeur.eql?
est une comparaison d'égalité qui est cohérente avec la façon dont le hachage est calculé, c'est-à-direa.eql?(b)
qui le garantita.hash == b.hash
. Il ne compare pas simplement les codes de hachage.bar === foo
et nonfoo === bar
? J'espère que ce dernier est correct et qu'il est important car le compilateur appelle le côté gauche: === ``bar === foo
: Ruby utilise la valeur de casse sur le côté gauche et la variable de casse sur le côté droit. Cela peut être lié à l'évitement des NPE (Null Pointer Exceptions).Opérateurs d'égalité: == et! =
L'opérateur ==, également appelé égal ou double égal, renverra true si les deux objets sont égaux et false s'ils ne le sont pas.
L'opérateur! =, Également connu sous le nom d'inégalité, est l'opposé de ==. Il retournera vrai si les deux objets ne sont pas égaux et faux s'ils sont égaux.
Notez que deux tableaux avec les mêmes éléments dans un ordre différent ne sont pas égaux, les versions majuscules et minuscules de la même lettre ne sont pas égales et ainsi de suite.
Lorsque vous comparez des nombres de différents types (par exemple, entier et flottant), si leur valeur numérique est la même, == renvoie true.
égal?
Contrairement à l'opérateur == qui teste si les deux opérandes sont égaux, la méthode égale vérifie si les deux opérandes se réfèrent au même objet. Il s'agit de la forme d'égalité la plus stricte en Ruby.
Exemple: a = "zen" b = "zen"
Dans l'exemple ci-dessus, nous avons deux chaînes avec la même valeur. Cependant, ce sont deux objets distincts, avec des ID d'objet différents. Par conséquent, l'égal? retournera false.
Essayons encore, seulement cette fois b sera une référence à a. Notez que l'ID d'objet est le même pour les deux variables, car elles pointent vers le même objet.
eql?
Dans la classe Hash, l'eql? méthode utilisée pour tester l'égalité des clés. Un certain fond est nécessaire pour expliquer cela. Dans le contexte général de l'informatique, une fonction de hachage prend une chaîne (ou un fichier) de n'importe quelle taille et génère une chaîne ou un entier de taille fixe appelé hashcode, communément appelé uniquement hachage. Certains types de codes de hachage couramment utilisés sont MD5, SHA-1 et CRC. Ils sont utilisés dans les algorithmes de chiffrement, l'indexation des bases de données, la vérification de l'intégrité des fichiers, etc. Certains langages de programmation, tels que Ruby, fournissent un type de collection appelé table de hachage. Les tables de hachage sont des collections de type dictionnaire qui stockent les données par paires, composées de clés uniques et de leurs valeurs correspondantes. Sous le capot, ces clés sont stockées sous forme de codes de hachage. Les tables de hachage sont communément appelées simplement des hachages. Remarquez comment le mot hachage peut faire référence à un code de hachage ou à une table de hachage.
Ruby fournit une méthode intégrée appelée hachage pour générer des codes de hachage. Dans l'exemple ci-dessous, il prend une chaîne et retourne un hashcode. Notez que les chaînes ayant la même valeur ont toujours le même code de hachage, même s'il s'agit d'objets distincts (avec des ID d'objet différents).
La méthode de hachage est implémentée dans le module Kernel, inclus dans la classe Object, qui est la racine par défaut de tous les objets Ruby. Certaines classes telles que Symbol et Integer utilisent l'implémentation par défaut, d'autres comme String et Hash fournissent leurs propres implémentations.
Dans Ruby, lorsque nous stockons quelque chose dans un hachage (collection), l'objet fourni sous forme de clé (par exemple, une chaîne ou un symbole) est converti et stocké en tant que code de hachage. Plus tard, lors de la récupération d'un élément du hachage (collection), nous fournissons un objet sous forme de clé, qui est converti en code de hachage et comparé aux clés existantes. En cas de correspondance, la valeur de l'élément correspondant est renvoyée. La comparaison est faite en utilisant l'eql? méthode sous le capot.
Dans la plupart des cas, l'eql? se comporte de manière similaire à la méthode ==. Il existe cependant quelques exceptions. Par exemple, eql? n'effectue pas de conversion de type implicite lors de la comparaison d'un entier à un flottant.
Opérateur d'égalité de casse: ===
De nombreuses classes intégrées de Ruby, telles que String, Range et Regexp, fournissent leurs propres implémentations de l'opérateur ===, également connu sous le nom d'égalité de casse, triple égal ou triple. Parce qu'il est implémenté différemment dans chaque classe, il se comportera différemment selon le type d'objet auquel il a été appelé. Généralement, elle renvoie true si l'objet de droite "appartient à" ou "est membre de" l'objet de gauche. Par exemple, il peut être utilisé pour tester si un objet est une instance d'une classe (ou l'une de ses sous-classes).
Le même résultat peut être obtenu avec d'autres méthodes qui sont probablement les mieux adaptées au travail. Il est généralement préférable d'écrire du code facile à lire en étant aussi explicite que possible, sans sacrifier l'efficacité et la concision.
Notez que le dernier exemple a renvoyé false car les entiers tels que 2 sont des instances de la classe Fixnum, qui est une sous-classe de la classe Integer. Le ===, is_a? et instance_of? Les méthodes renvoient true si l'objet est une instance de la classe donnée ou des sous-classes. La méthode instance_of est plus stricte et ne renvoie true que si l'objet est une instance de cette classe exacte, pas une sous-classe.
L'is_a? et kind_of? Les méthodes sont implémentées dans le module Kernel, qui est mélangé par la classe Object. Les deux sont des alias de la même méthode. Vérifions:
Kernel.instance_method (: kind_of?) == Kernel.instance_method (: is_a?) # Sortie: => true
Implémentation de la gamme ===
Lorsque l'opérateur === est appelé sur un objet de plage, il renvoie vrai si la valeur de droite se situe dans la plage de gauche.
N'oubliez pas que l'opérateur === appelle la méthode === de l'objet de gauche. Donc (1..4) === 3 est équivalent à (1..4). === 3. En d'autres termes, la classe de l'opérande de gauche définira quelle implémentation de la méthode === sera appelé, donc les positions d'opérande ne sont pas interchangeables.
Mise en œuvre regexp de ===
Renvoie true si la chaîne de droite correspond à l'expression régulière de gauche. / zen / === "pratiquer zazen aujourd'hui" # Sortie: => true # est le même que "pratiquer zazen aujourd'hui" = ~ / zen /
Utilisation implicite de l'opérateur === sur les instructions case / when
Cet opérateur est également utilisé sous le capot sur les déclarations case / when. C'est son utilisation la plus courante.
Dans l'exemple ci-dessus, si Ruby avait implicitement utilisé l'opérateur double égal (==), la plage 10..20 ne serait pas considérée comme égale à un entier tel que 15. Ils correspondent parce que l'opérateur triple égal (===) est implicitement utilisé dans toutes les instructions case / when. Le code de l'exemple ci-dessus équivaut à:
Opérateurs de correspondance de motifs: = ~ et! ~
Les opérateurs = ~ (égal-tilde) et! ~ (Bang-tilde) sont utilisés pour faire correspondre les chaînes et les symboles aux motifs d'expression régulière.
L'implémentation de la méthode = ~ dans les classes String et Symbol attend une expression régulière (une instance de la classe Regexp) comme argument.
L'implémentation dans la classe Regexp attend une chaîne ou un symbole comme argument.
Dans toutes les implémentations, lorsque la chaîne ou le symbole correspond au modèle Regexp, il renvoie un entier qui est la position (index) de la correspondance. S'il n'y a pas de correspondance, il renvoie zéro. Souvenez-vous que, dans Ruby, toute valeur entière est "true" et nil est "falsy", donc l'opérateur = ~ peut être utilisé dans les instructions if et les opérateurs ternaires.
Les opérateurs de filtrage sont également utiles pour écrire des instructions if plus courtes. Exemple:
L'opérateur! ~ Est l'opposé de = ~, il renvoie vrai quand il n'y a pas de correspondance et faux s'il y a une correspondance.
Plus d'informations sont disponibles sur ce blog .
la source
:zen === "zen"
retourne fauxRuby expose plusieurs méthodes différentes pour gérer l'égalité:
Continuez à lire en cliquant sur le lien ci-dessous, cela m'a donné une compréhension résumée claire.
J'espère que cela aide les autres.
la source
=== # --- égalité de cas
== # --- égalité générique
les deux fonctionnent de manière similaire mais "===" fait même des déclarations de casse
ici la différence
la source
a==b
làa===b
. Maisa===b
est beaucoup plus puissant.===
n'est pas symétrique eta===b
signifie une chose très différente deb===a
, encore moinsa==b
.Je voudrais développer l'
===
opérateur.===
n'est pas un opérateur d'égalité!Ne pas.
Faisons vraiment passer ce point.
Vous connaissez peut-être
===
un opérateur d'égalité en Javascript et PHP, mais ce n'est tout simplement pas un opérateur d'égalité dans Ruby et sa sémantique est fondamentalement différente.Alors qu'est-ce que ça
===
fait?===
est l'opérateur de correspondance de motifs!===
correspond aux expressions régulières===
vérifie l'appartenance à la plage===
vérifie être une instance d'une classe===
appelle des expressions lambda===
vérifie parfois l'égalité, mais surtout pasAlors, comment cette folie a-t-elle un sens?
Enumerable#grep
utilise en===
internecase when
instructions utilisées en===
internerescue
utilise en===
interneC'est pourquoi vous pouvez utiliser des expressions régulières, des classes et des plages et même des expressions lambda dans une
case when
instruction.Quelques exemples
Tous ces exemples fonctionnent
pattern === value
aussi avec lagrep
méthode.la source
J'ai écrit un test simple pour tout ce qui précède.
la source