Quelle est la différence entre l'égalité?, eql?, ===,==?

j'essaie de comprendre la différence entre ces quatre méthodes. Je sais par défaut que == appelle la méthode equal? qui renvoie true lorsque les deux opérandes se réfèrent exactement au même objet.

=== appelle aussi par défaut == qui appelle equal? ... Ok, donc si toutes ces trois méthodes ne sont pas dépassées, alors je suppose === , == et equal? font exactement la même chose?

c'est Maintenant eql? . Qu'est-ce faire (par défaut)? Est-ce qu'il fait un appel à l'identification de l'opérande?

pourquoi Ruby a-t-elle autant de signes d'égalité? Sont-ils censés diffèrent dans la sémantique?

490
demandé sur Freedom_Ben 2011-08-23 10:13:58
la source

7 ответов

je vais citer fortement la documentation objet ici, parce que je pense qu'il a quelques grandes explications. Je vous encourage à le lire, ainsi que la documentation pour ces méthodes car elles sont dépassées dans d'autres classes, comme String .

note de Côté: si vous voulez les essayer pour vous-même sur des objets différents, utiliser quelque chose comme ceci:

class Object
  def all_equals(o)
    ops = [:==, :===, :eql?, :equal?]
    Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]
  end
end

"a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false}

== - "égalité" Générique

au niveau de l'objet, == retourne true seulement si obj et other sont le même objet. Typiquement, cette méthode est dépassée dans les classes descendantes pour fournir une signification spécifique à la classe.

c'est la comparaison la plus courante, et donc le lieu le plus fondamental où vous (en tant qu'auteur d'une classe) obtenez de décider si deux les objets sont "égaux" ou pas.

=== - égalité de cas

pour objet de classe, effectivement le même que l'appel #== , mais typiquement dépassé par les descendants pour fournir la sémantique significative dans les déclarations de cas.

C'est incroyablement utile. Exemples de choses qui ont des implémentations intéressantes === :

  • Gamme
  • Regex
  • Proc (en Ruby 1.9)

donc vous pouvez faire des choses comme:

case some_object
when /a regex/
  # The regex matches
when 2..4
  # some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
  # the lambda returned true
end

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 === mise en œuvre, vous pouvez obtenir personnalisé case sémantique.

eql? - Hash l'égalité

la méthode eql? retourne true si obj et other se réfèrent à la même clé de hachage. Ce critère est utilisé par Hash pour tester l'égalité des membres. pour les objets de la classe Object , eql? est synonyme de == . Les sous-classes poursuivent normalement cette tradition en liant eql? à leur méthode == , mais il y a des exceptions. Les types Numeric , par exemple, effectuer la conversion de type à travers == , mais pas à travers eql? , donc:

1 == 1.0     #=> true
1.eql? 1.0   #=> false

donc vous êtes libre d'annuler ceci pour vos propres utilisations, ou vous pouvez annuler == et utiliser alias :eql? :== donc les deux méthodes se comportent de la même manière.

equal? - comparaison d'identité

contrairement à == , la méthode equal? ne doit jamais être supplantée par des sous-classes: elle est utilisé pour déterminer l'identité de l'objet (qui est, a.equal?(b) iff a est le même objet que b ).

c'est effectivement une comparaison de pointeur.

716
répondu jtbandes 2018-09-21 07:00:49
la source

j'adore la réponse de jtbandes, mais comme elle est assez longue, je vais ajouter ma propre réponse compacte:

== , === , eql? , equal?

4 comparateurs, c'est à dire. 4 façons de comparer 2 objets, en rubis.

Comme, dans Ruby, tous les comparateurs (et la plupart des opérateurs) sont en fait des appels de méthode, vous pouvez changer, écraser, et définir la sémantique de ces méthodes de comparaison m'. Toutefois, il est important de comprendre, lorsque le langage interne de Ruby construit utiliser quel comparateur:

== (comparaison de valeur)

Ruby utilise: = = partout pour comparer les valeurs de 2 objets, par exemple. Valeurs de hachage:

{a: 'z'}  ==  {a: 'Z'}    # => false
{a: 1}    ==  {a: 1.0}    # => true

=== (comparaison de cas)

Ruby utilise: = = = au cas / quand construire. Les extraits de code suivants sont logiquement identiques:

case foo
  when bar;  p 'do something'
end

if bar === foo
  p 'do something'
end

eql? (de Hachage de la comparaison clé)

Ruby utilise: eql? (en combinaison avec la méthode de hachage) pour comparer les Mot-clés. Dans la plupart des classes :eql? est identique :==.

Connaissance de: eql? est seulement important, quand vous voulez créer vos propres classes spéciales:

class Equ
  attr_accessor :val
  alias_method  :initialize, :val=
  def hash()           self.val % 2             end
  def eql?(other)      self.hash == other.hash  end
end

h = {Equ.new(3) => 3,  Equ.new(8) => 8,  Equ.new(15) => 15}    #3 entries, but 2 are :eql?
h.size            # => 2
h[Equ.new(27)]    # => 15

Note: Le L'ensemble Ruby-class couramment utilisé s'appuie également sur Hash-key-comparaison.

equal? (comparaison d'identité d'objet)

Ruby utilise :l'égalité? pour vérifier si deux objets sont identiques. Cette méthode (de la classe BasicObject) n'est pas supposée être écrasée.

obj = obj2 = 'a'
obj.equal? obj2       # => true
obj.equal? obj.dup    # => false
39
répondu Andreas Rayo Kniep 2015-04-06 03:42:27
la source

opérateurs d'Égalité: == et !=

l'opérateur==, également connu sous le nom d'égalité ou de double égalité, retournera true si les deux objets sont égaux et false s'ils ne le sont pas.

"koan" == "koan" # Output: => true

The != opérateur, alias inégalité ou bang-tilde, est le contraire de ==. Il retournera true si les deux objets ne sont pas égaux et false s'ils sont égaux.

"koan" != "discursive thought" # Output: => true

noter que deux tableaux avec les mêmes éléments dans un différent ordre ne sont pas égaux, majuscules et minuscules versions de la même lettre ne sont pas égaux et ainsi de suite.

en comparant des nombres de différents types (par exemple, entier et flottant), si leur valeur numérique est la même, = = retournera true.

2 == 2.0 # Output: => true

l'égalité?

contrairement à l'opérateur = = qui teste si les deux opérandes sont égales, la méthode equal vérifie si les deux opérandes se réfèrent au même objet. C'est la forme la plus stricte de égalité dans Ruby.

exemple: Zen" b = " zen "

a.object_id  # Output: => 20139460
b.object_id  # Output :=> 19972120

a.equal? b  # Output: => false

dans l'exemple ci-dessus, nous avons deux chaînes avec la même valeur. Cependant, il s'agit de deux objets distincts, avec des identificateurs d'objet différents. Par conséquent, l'égalité? méthode retournera false.

essayons encore, seulement cette fois b sera une référence à A. Notez que l'ID objet est le même pour les deux variables, car elles pointent vers le même objet.

a = "zen"
b = a

a.object_id  # Output: => 18637360
b.object_id  # Output: => 18637360

a.equal? b  # Output: => true

eql?

dans la classe Hash, l'eql? méthode elle est utilisée pour tester les clés pour l'égalité. Il faut un certain bagage 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é seulement hachage. Certains types de hashcode couramment utilisés sont MD5, SHA-1, et CRC. Ils sont utilisés dans les algorithmes de cryptage, l'indexation de base de données, vérification de l'intégrité, etc. Certains langages de programmation, comme Ruby, fournissent un type de collection appelé table de hachage. Les tables de hachage sont des collections de type dictionnaire qui stockent des 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 hashcodes. Les tables de hachage sont communément appelées juste des hachures. Remarquez comment le mot hashcan se réfère à un hashcode ou à une table de hachage. Dans le contexte de la programmation Ruby, le mot hash se réfère presque toujours à la collection de dictionnaires.

Ruby fournit une méthode intégrée appelée hachage pour générer des hashcodes. Dans l'exemple ci-dessous, il prend une chaîne et renvoie un hashcode. Remarquez que les chaînes avec la même valeur ont toujours le même hashcode, même si ce sont des objets distincts (avec des identifiants d'objet différents).

"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547

la méthode hash est implémentée dans le module du noyau, inclus dans la classe objet, qui est la racine par défaut de tout Ruby objet. 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.

Symbol.instance_method(:hash).owner  # Output: => Kernel
Integer.instance_method(:hash).owner # Output: => Kernel

String.instance_method(:hash).owner  # Output: => String
Hash.instance_method(:hash).owner  # Output: => Hash

dans Ruby, lorsque nous stockons quelque chose dans un hash (collection), l'objet fourni comme une clé (par exemple, chaîne ou symbole) est converti et stocké comme un hashcode. Plus tard, lors de la récupération d'un élément du hachage (collection), nous fournissons un objet comme clé, qui est converti en hashcode et comparé à les clés existantes. Si il y a une correspondance, la valeur de l'élément correspondant est retourné. La comparaison est faite en utilisant l'eql? méthode sous la hotte.

"zen".eql? "zen"    # Output: => true
# is the same as
"zen".hash == "zen".hash # Output: => true

dans la plupart des cas, l'eql? la méthode se comporte de la même façon que la méthode==. Cependant, il existe quelques exceptions. Par exemple, eql? n'effectue pas la conversion de type implicite en comparant un entier à un flottant.

2 == 2.0    # Output: => true
2.eql? 2.0    # Output: => false
2.hash == 2.0.hash  # Output: => false

Cas opérateur d'égalité: ===

plusieurs des classes intégrées de Ruby, telles que String, Range et Regexp, fournissent leurs propres implémentations de l'opérateur===, aussi connu sous le nom de case-equality, Triple equals ou threeequals. Parce qu'il est implémenté différemment dans chaque classe, il se comportera différemment selon le type d'objet sur lequel il a été appelé. Généralement, elle renvoie true si l'objet sur la droite "appartient à" ou "est un membre de" l'objet sur la gauche. Par exemple, il peut être utilisé pour tester si un un objet est une instance d'une classe (ou un de ses sous-classes).

String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

Le même résultat peut être obtenu avec d'autres méthodes qui sont probablement les mieux adaptés pour le travail. Il est généralement préférable d'écrire du code qui est facile à lire en étant aussi explicite que possible, sans sacrifier l'efficacité et la concision.

2.is_a? Integer   # Output: => true
2.kind_of? Integer  # Output: => true
2.instance_of? Integer # Output: => false

noter le dernier exemple retourné false parce que des entiers tels que 2 sont des instances de la classe Fixnum, qui est un sous-classe de la classe Integer. L' ===, is_a? et instance_of? méthodes renvoie true si l'objet est une instance de la classe donnée ou toutes les 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.

La is_a? et kind_of? les méthodes sont implémentées dans le module du noyau, qui est mélangé par la classe objet. Les deux sont des alias de la même méthode. Vérifions:

Noyau.instance_method (: kind_of?) == Noyau.instance_method (: is_a?) # Output: => true

mise en œuvre de = = =

quand l'opérateur === est appelé sur un objet range, il renvoie true si la valeur à droite se situe dans la plage à gauche.

(1..4) === 3  # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6  # Output: => false

("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false

rappelez-vous que l'opérateur === invoque la méthode === de l'objet de gauche. So (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ée, de sorte que les positions de l'opérande ne sont pas interchangeables.

Regexp mise en Œuvre de l' ===

renvoie true si la chaîne de caractères à droite correspond à l'expression régulière à gauche. /zen/ === "la pratique de zazen aujourd'hui" # Sortie: => true # est le même que "la pratique de zazen aujourd'hui"=~ /zen/

utilisation implicite de l'opérateur = = = cas/quand déclarations

cet opérateur est également utilisé sous la hotte sur les instructions case/when. C'est son usage le plus courant.

minutes = 15

case minutes
  when 10..20
    puts "match"
  else
    puts "no match"
end

# Output: match

dans l'exemple ci-dessus, si Ruby avait implicitement utilisé l'opérateur double equal (==), la gamme 10..20 ne serait pas considéré comme égal à un entier tel que 15. Ils concordent parce que l'opérateur Triple equal (===) est implicitement utilisé dans tous les énoncés case/when. Le code dans l'exemple ci-dessus est équivalente à:

if (10..20) === minutes
  puts "match"
else
  puts "no match"
end

Pattern matching opérateurs: =~ et !~

= ~ (égale-tilde) et ! les opérateurs ~ (bang-tilde) sont utilisés pour apparier les chaînes et les symboles avec les motifs regex.

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.

"practice zazen" =~ /zen/   # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil

:zazen =~ /zen/    # Output: => 2
:zazen =~ /discursive thought/  # Output: => nil

la mise en œuvre dans la classe Regexp attend une chaîne de caractères ou un symbole comme argument.

/zen/ =~ "practice zazen"  # Output: => 11
/zen/ =~ "discursive thought" # Output: => nil

dans toutes les implémentations, lorsque la chaîne ou le symbole correspond au motif Regexp, il retourne un entier qui est la position (index) de la correspondance. S'il n'y a pas de correspondance, elle renvoie zéro. Rappelez-vous que, dans Ruby, toute valeur entière est "truthy" et nil est "falsy", de sorte que l'opérateur =~ peut être utilisé dans les déclarations if et les opérateurs ternaires.

puts "yes" if "zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes

Les opérateurs d'appariement de modèle sont également utiles pour écrire des déclarations if plus courtes. Exemple:

if meditation_type == "zazen" || meditation_type == "shikantaza" || meditation_type == "kinhin"
  true
end
Can be rewritten as:
if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
  true
end

The !~ l'opérateur est à l'opposé de =~, elle renvoie true quand il n'y a pas de match, et false si il y a un match.

plus d'informations sont disponibles à ce billet de blog .

22
répondu BrunoFacca 2016-07-02 23:39:25
la source

=== #---égalité devant la loi

== #--- générique de l'égalité

les deux œuvres sont similaires mais "= = = "même les énoncés de cas

"test" == "test"  #=> true
"test" === "test" #=> true

ici la différence

String === "test"   #=> true
String == "test"  #=> false
7
répondu Kishore Mohan 2014-04-22 13:13:58
la source

Ruby expose plusieurs méthodes différentes pour traiter l'égalité:

A. égaux?(b) # l'identité de l'objet a et b font référence au même objet

A. eql?B) # équivalence objet - a et b ont la même valeur

A == B # l'équivalence d'objet - a et b ont la même valeur avec la conversion de type.

continuer la lecture en cliquant sur le lien ci-dessous, il m'a donné une compréhension résumée claire.

https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers

Espère que cela aide les autres.

6
répondu kalibbala 2015-05-25 20:59:23
la source

je voudrais développer l'opérateur === .

=== n'est pas un opérateur d'égalité!

Not.

faisons passer ce point.

vous pourriez être familier avec === en tant qu'opérateur d'égalité en Javascript et PHP, mais ce n'est tout simplement pas un opérateur d'égalité en Ruby et a une sémantique fondamentalement différente.

alors qu'est-ce que === do?

=== est l'opérateur de correspondance des motifs!

  • === correspond à des expressions régulières
  • === vérifie adhésion plage
  • === les contrôles étant une instance d'une classe
  • === appelle les expressions lambda
  • === parfois, vérifie l'égalité, mais la plupart du temps, il n'est pas

alors comment cette folie a-t-elle un sens?

  • Enumerable#grep utilise === interne
  • case when instructions d'utilisation === interne
  • fait Amusant, rescue utilise === interne

C'est pourquoi vous pouvez utiliser des expressions régulières et des classes et des gammes et même des expressions lambda dans une déclaration case when .

quelques exemples

case value
when /regexp/
  # value matches this regexp
when 4..10
  # value is in range
when MyClass
  # value is an instance of class
when ->(value) { ... }
  # lambda expression returns true
when a, b, c, d
  # value matches one of a through d with `===`
when *array
  # value matches an element in array with `===`
when x
  # values is equal to x unless x is one of the above
end

tous ces exemples fonctionnent aussi avec pattern === value , ainsi qu'avec la méthode grep .

arr = ['the', 'quick', 'brown', 'fox', 1, 1, 2, 3, 5, 8, 13]
arr.grep(/[qx]/)                                                                                                                            
# => ["quick", "fox"]
arr.grep(4..10)
# => [5, 8]
arr.grep(String)
# => ["the", "quick", "brown", "fox"]
arr.grep(1)
# => [1, 1]
4
répondu akuhn 2017-03-12 05:02:57
la source

j'ai écrit un test simple pour tout ce qui précède.

def eq(a, b)
  puts "#{[a, '==',  b]} : #{a == b}"
  puts "#{[a, '===', b]} : #{a === b}"
  puts "#{[a, '.eql?', b]} : #{a.eql?(b)}"
  puts "#{[a, '.equal?', b]} : #{a.equal?(b)}"
end

eq("all", "all")
eq(:all, :all)
eq(Object.new, Object.new)
eq(3, 3)
eq(1, 1.0)
-8
répondu Tom Phan 2014-04-26 03:02:49
la source

Autres questions sur ruby operators equality comparison