Koks skirtumas tarp lygių?, Eql?, === ir ==?

Bandau suprasti šių keturių metodų skirtumą. Pagal nutylėjimą žinau, kad == vadina equal? metodą equal? , kuris grįžta tiesa, kai abu operandai nurodo tą patį objektą.

=== pagal nutylėjimą taip pat skambina == , kuris skamba equal? ... gerai, taigi, jei visi šie trys metodai nepaisomi, manau, kad === , == ir equal? daryti tą patį?

Dabar eql? . Ką tai daro (pagal nutylėjimą)? Ar skambutis atlieka operandų maišą / id?

Kodėl Ruby turi tiek daug lygių ženklų? Ar jie turėtų būti skirtingi semantikoje?

502
23 авг. rinkinys denniss Rgp 23 2011-08-23 09:13 '11 at 9:13 2011-08-23 09:13
@ 7 atsakymai

Labai daug cituoju dokumentus apie šį objektą , nes manau, kad tai turi keletą puikių paaiškinimų. Aš rekomenduoju perskaityti jį ir šių metodų dokumentus, nes jie iš naujo apibrėžti kitose klasėse, pvz., Eilutėje .

Pastaba: jei norite išbandyti jį patys skirtinguose objektuose, naudokite tai:

 class Object def all_equals(o) ops = [:==, :===, :eql?, :equal?] Hash[ops.map( {|s| send(s, o) })] end end "a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false} 

== - bendra „lygybė“

Objekto lygiu == grįžta tiesa tik tuo atveju, jei obj ir other yra tas pats objektas. Paprastai šis metodas iš naujo apibrėžiamas palikuonių klasėse, kad būtų gauta konkrečios klasės vertė.

Tai yra labiausiai paplitęs palyginimas, todėl svarbiausia vieta, kur jūs (kaip klasės autorius) nuspręsite, ar du objektai yra „lygūs“, ar ne.

=== - atvejo lygybė

Objektų klasei jis iš tikrųjų yra tas pats, kaip skambinant #== , bet palikuonys paprastai ignoruoja, kad pateiktų reikšmingą semantiką atvejo pareiškimuose.

Tai yra neįtikėtinai naudinga. Įdomių įgyvendinimo pavyzdžių pavyzdžiai === :

  • Diapazonas
  • Regex
  • Proc (Ruby 1.9)

Taigi galite daryti tokius dalykus:

 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 

Žr mano atsakymą čia , kad galėtum case , kaip „ Regex gali padaryti kodą daug švaresniu pavyzdžiu. Ir, žinoma, suteikdami savo įgyvendinimą === , galite gauti individualų case semantiką.

eql? - Hash lygybė

eql? metodas eql? grįžta tiesa, jei obj ir other nurodo tą patį maišos raktą. Tai naudoja Hash kad patikrintų narius lygybei. Klasės Object eql? , eql? yra == sinonimas. eql? poklasiai paprastai tęsia šią tradiciją, lygindami eql? jų viršijęs metodas == , tačiau yra išimčių. Pavyzdžiui, Numeric , pvz., Tipo konvertavimui atlikti su == , bet ne su eql? todėl:

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

Taigi galite jį iš naujo apibrėžti savo reikmėms arba iš naujo apibrėžti == ir naudoti alias :eql? :== alias :eql? :== kad abu metodai veiktų vienodai.

equal? - tapatybės palyginimas

Skirtingai nuo == , equal? metodas equal? niekada negalima iš naujo apibrėžti poklasiais: ar jis naudojamas objekto tapatybei nustatyti (ty a.equal?(b) iff a yra tas pats objektas, kaip ir b ).

Tai yra veiksmingas rodyklės palyginimas.

728
23 авг. atsakymas pateikiamas 23 d. 2011-08-23 09:25 '11 at 9:25 am 2011-08-23 09:25

Man patinka atsakymas į „jtbandes“, bet kadangi tai gana ilgai, pridėsiu savo kompaktišką atsakymą:

== , === , eql? equal?
4 komparatoriai, t.y. 4 būdai palyginti 2 objektus Ruby.
Kaip ir Ruby, visi lyginamieji elementai (ir dauguma operatorių) iš tikrųjų yra skambučių metodai, galite pakeisti, perrašyti ir apibrėžti šių palyginimo metodų semantiką. Tačiau svarbu suprasti, kada lyginamoji priemonė naudojama vidinės Ruby kalbos konstrukcijose:

== (vertės palyginimas)
Ruby naudoja: == visur, pavyzdžiui, lygindama dviejų objektų vertes . Hash vertės:

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

=== (atvejo palyginimas)
Ruby naudoja: === atveju / kai konstruoja. Šie kodo fragmentai logiškai identiški:

 case foo when bar; p 'do something' end if bar === foo p 'do something' end 
border=0

eql? (maišos raktų palyginimas)
Ruby naudoja: eql? (kartu su maišos metodu) lyginti maišos raktus. Daugelyje klasių: eql? atitinka: ==.
Žinios apie: eql? svarbu, kai norite sukurti savo specialius užsiėmimus:

 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 

Pastaba Dažniausiai naudojamas „Ruby“ klasės rinkinys taip pat remiasi „hash key“ palyginimu.

equal? (objektų tapatybės palyginimas)
Ruby naudoja: lygus? patikrinti, ar du objektai yra identiški. Šis metodas (klasė BasicObject) neturėtų būti perrašytas.

 obj = obj2 = 'a' obj.equal? obj2 # => true obj.equal? obj.dup # => false 
41
06 апр. Andreas Rayo Kniep atsakymas 06 Bal. 2015-04-06 03:42 '15 at 3:42 2015-04-06 03:42

Lygių galimybių operatoriai: == ir! =

Operatorius ==, taip pat žinomas kaip lygybė arba dviguba lygybė, grįžta tiesa, jei abu objektai yra lygūs ir klaidingi, jei jie nėra.

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

Operatorius! =, AKA arba bang-tilde nelygybė priešais ==. Ji grąžinama tiesa, jei abu objektai yra lygūs ir klaidingi, jei jie yra lygūs.

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

Atkreipkite dėmesį, kad dvi matricos, turinčios tuos pačius elementus kitoje eilutėje, nėra lygios, didžiosios ir mažosios raidės tos pačios raidės nėra vienodos ir pan.

Palyginus skirtingų tipų numerius (pvz., Sveikąjį skaičių ir plūdę), jei jų skaitmeninė vertė yra tokia pati, == grįžta tiesa.

 2 == 2.0 # Output: => true 

vistiek

Skirtingai nuo == operatoriaus, kuris patikrina, ar abu operandai yra lygūs, lygybės metodas tikrina, ar šie du operandai priklauso tam pačiam objektui. Tai yra griežčiausia Ruby lygybės forma.

Pavyzdys: a = "zen" b = "zen"

 a.object_id # Output: => 20139460 b.object_id # Output :=> 19972120 a.equal? b # Output: => false 

Pirmiau pateiktame pavyzdyje yra dvi tos pačios vertės eilutės. Tačiau jie yra du skirtingi objektai su skirtingais objekto identifikatoriais. Todėl lygus? metodas grąžina klaidingą.

Bandykite dar kartą, tik šiuo metu b bus nuoroda į. Atkreipkite dėmesį, kad abiejų kintamųjų objektų identifikatorius yra tas pats, nes jie nurodo tą patį objektą.

 a = "zen" b = a a.object_id # Output: => 18637360 b.object_id # Output: => 18637360 a.equal? b # Output: => true 

EQL?

„Hash“ klasėje išraiška eql? Šis metodas naudojamas patvirtinti lygybės raktus. Tam reikia paaiškinti tam tikrą pagrindą. Bendrosios skaičiavimo kontekste maišos funkcija atlieka bet kokio dydžio eilutę (arba failą) ir generuoja fiksuoto dydžio eilutę arba sveikąjį skaičių, vadinamą hashcode, paprastai vadinamą tik „hash“. Kai kurie dažniausiai naudojami maišos kodų tipai yra MD5, SHA-1 ir CRC. Jie naudojami šifravimo algoritmuose, duomenų bazės indeksavimo, failų vientisumo tikrinimo ir kt. Kai kurios programavimo kalbos, pvz., „Ruby“, suteikia kolekcijos tipą, vadinamą maišos lentele. „Hash“ lentelės yra žodynų kolekcijos, saugančios duomenis poromis, susidedančios iš unikalių raktų ir jų atitinkamų verčių. Po gaubtu šie raktai yra saugomi kaip maišos kodai. Hash'o lentelės paprastai vadinamos tiesiog hashes. Atkreipkite dėmesį, kaip žodis „hash“ gali būti susijęs su maišos kodu arba maišymo stalu. Ruby programavimo kontekste žodis „hash“ beveik visada reiškia žodyno kolekciją.

Ruby pateikia įmontuotą metodą, vadinamą „hash“, kad generuotų maišos kodus. Toliau pateiktame pavyzdyje jis užima eilutę ir grąžina maišos kodą. Atkreipkite dėmesį, kad tos pačios vertės linijos visada turi tą patį maišos kodą, nors jos yra skirtingi objektai (su skirtingais objekto identifikatoriais).

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

Maišos metodas įgyvendinamas branduolio modulyje, įtrauktame į Objektų klasę, kuri yra visų Ruby objektų numatytoji šaknis. Kai kurios klasės, pvz., „Simbolis“ ir „Integer“, naudoja numatytąjį įgyvendinimą, kiti, pvz., „String“ ir „Hash“, pateikia savo įgyvendinimą.

 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 

Ruby, kai saugome kažką hash (kolekcija), objektas, pateiktas kaip raktas (pvz., Eilutė arba simbolis) yra konvertuojamas ir saugomas kaip maišos kodas. Vėliau, atkuriant elementą iš maišos (kolekcijos), mes pateikiame objektą kaip raktą, kuris paverčiamas maišos kodu ir palyginamas su esamais raktais. Jei yra rungtynės, atitinkamo elemento vertė grąžinama. Palyginimas atliekamas naudojant lygtį, esantį po gaubtu.

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

Daugeliu atvejų lygties metodas veikia panašiai kaip == metodas. Tačiau yra keletas išimčių. Pavyzdžiui, eql? neatlieka netiesioginio tipo konversijos, kai lyginama visa su plūde.

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

Atvejo lygybės operatorius: ===

Daugelis įmontuotų Ruby klasių, pvz., Eilutė, diapazonas ir „Regexp“, pateikia savo === operatorių diegimą, taip pat žinomas kaip „lygiaverčiai“, „trigubai lygūs“ arba „trys“. Kadangi kiekvienoje klasėje jis įgyvendinamas skirtingai, jis elgsis skirtingai, priklausomai nuo objekto tipo, kuriam jis buvo pavadintas. Paprastai jis grąžinamas teisingai, jei dešinėje pusėje esantis objektas yra „kairėje“ arba „yra narys“. Pavyzdžiui, galite naudoti jį patikrinti, ar objektas yra klasės (arba vieno iš jo poklasių) pavyzdys.

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

Tas pats rezultatas gali būti pasiektas naudojant kitus metodus, kurie geriausiai tinka darbui. Paprastai geriau rašyti kodą, kurį būtų lengva skaityti, kaip įmanoma aiškiau, neprarandant efektyvumo ir glaustumo.

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

Atkreipkite dėmesį, kad paskutinis pavyzdys grąžina false, nes sveikieji skaičiai, pvz., 2, yra klasės Fixnum atvejai, kurie yra klasės Integer poklasis. ===, is_a? ir pavyzdys? metodai grįžta tiesa, jei objektas yra šios klasės ar bet kokių poklasių pavyzdys. Pavyzdys_of metodas yra griežtesnis ir grąžinamas tiesa, jei objektas yra šios tikslios klasės egzempliorius, o ne poklasis.

is_a? ir kind_of? metodai yra įgyvendinami branduolio modulyje, kuris yra sumaišomas pagal objekto klasę. Abu yra to paties metodo slapyvardžiai. Tegul ji bus patikrinta:

Kernel.instance_method (: kind_of?) == Kernel.instance_method (: is_a?) # Išėjimas: => tiesa

Implanto diapazonas ===

Kai === operatorius vadinamas diapazono objektu, jis grąžinamas tiesa, jei dešinėje esanti vertė yra kairėje.

 (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 

Atminkite, kad === operatorius skambina === kairiojo objekto metodu. Taigi, (1..4) === 3 yra lygiavertis (1..4). === 3. Kitaip tariant, kairiojo operando klasė nustatys, kuris metodo įgyvendinimas === bus toks, kad operando pozicijos nebūtų pakeičiamos.

Regeneracija Regexp ===

Grąžinamas tiesa, jei dešinėje esanti eilutė atitinka įprastą išraišką kairėje. / zen / === "Praktika zazen šiandien" Išvada: => true # tas pats kaip "praktika zazen šiandien" = ~ / zen /

Netiesioginis operatorius naudoja === atvejo / kai pareiškimams

Šis teiginys taip pat naudojamas po gaubtu, skirtu atveju / kai pareiškimai. Tai jo dažniausiai naudojamas.

 minutes = 15 case minutes when 10..20 puts "match" else puts "no match" end # Output: match 

Pirmiau pateiktame pavyzdyje, jei Ruby netiesiogiai naudojo operatorių su dvigubu lygiu (==), diapazonas 10..20 nebūtų laikomas lygiu sveikam skaičiui, pvz. atvejis / kada. Šio pavyzdžio kodas yra lygiavertis:

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

Modelių atitikimo operatoriai: = ~ ir! ~

Operatoriai = ~ (lygus-tilde) ir! ~ (bang-tilde) naudojami styginiams ir simboliams suderinti su reguliariais raiškos modeliais.

Įgyvendinant metodą = ~ String ir Symbol klasėse, kaip argumentas, įprasta išraiška (Regexp klasės egzempliorius).

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

Įgyvendinimas „Regexp“ klasėje tikisi, kad eilutė ar simbolis bus argumentas.

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

Visose realizacijose, kai eilutė arba simbolis atitinka „Regexp“ modelį, jis grąžina sveikąjį skaičių, kuris yra rungtynės pozicija (indeksas). Jei nėra atitikimo, jis grąžina nulį. Atminkite, kad Ruby, bet kuris sveikasis skaičius yra „tiesa“, o nulis yra „klaidingas“, todėl = ~ operatorius gali būti naudojamas, jei pareiškimai ir trigubi pareiškimai.

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

Rašto atitikimo operatoriai taip pat naudingi rašant sutrumpintus teiginius. Pavyzdys:

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

Operatorius! ~ priešinga = ~, ji grįžta tiesa, jei nėra atitikimo, ir klaidinga, jei yra rungtynės.

Papildoma informacija pateikiama šiame dienoraščio įraše .

25
29 мая '16 в 19:47 2016-05-29 19:47 atsakymą pateikė BrunoFacca gegužės 29 d., 16 d., 19:47 19:47

=== # - Ekvivalentinė lygybė

== # --- bendra lygybė

abu jie veikia taip pat, bet „===“ netgi pateikia atvejų

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

yra skirtumas

 String === "test" #=> true String == "test" #=> false 
7
22 апр. Atsakymą pateikė Kishore Mohan balandžio 22 d 2014-04-22 12:13 „14, 12:13 2014-04-22 12:13

Ruby pateikia keletą skirtingų lygybės valdymo metodų:

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

Tikiuosi, kad tai padės kitiems.

6
11 апр. atsakymas pateikiamas kalibbala 11 balandžio. 2015-04-11 23:43 '15, 23:43, 2015-04-11 23:43

Norėčiau išplėsti operatorių === .

=== nėra lygybės operatorius!

ne

Leiskite man tai iš tikrųjų.

Jūs galite susipažinti su === kaip lygybės operatoriumi „Javascript“ ir „PHP“, tačiau tai tiesiog nėra lygybės operatorius Ruby'e ir turi iš esmės skirtingą semantiką.

Taigi, ką reiškia === ?

=== - šablono atitikimo operatorius!

  • === atitinka įprastas išraiškas
  • === tikrina diapazono narystę
  • === tikrina klasės egzempliorių
  • === sukelia lambda išraišką
  • === kartais tikrina lygybę, bet iš esmės tai nėra

Taigi, kaip šis protingumas yra prasmingas?

  • Enumerable#grep naudoja === viduje Operatoriai
  • case when naudojate === viduje
  • Pramogos, rescue naudoja === viduje

Štai kodėl galite naudoti reguliarias išraiškas, klases ir diapazonus ir net lambda išraiškas, case when .

Keletas pavyzdžių

 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 

Visi šie pavyzdžiai taip pat veikia su pattern === value , taip pat naudojant grep metodą.

 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
12 марта '17 в 5:02 2017-03-12 05:02 atsakymą pateikė akuhn kovo 12 '17, 17:02 2017-03-12 05:02

Aš parašiau paprastą testą visoms pirmiau nurodytoms.

 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
26 апр. Atsakymą pateikė Tom Phan balandžio 26 d 2014-04-26 02:02 '14, 2:02 2014-04-26 02:02

Kiti klausimai apie žymių arba Užduoti klausimą