ความแตกต่างระหว่างเท่ากับคืออะไร? eql ?, === และ ==?


552

ฉันพยายามเข้าใจความแตกต่างระหว่างสี่วิธีนี้ ฉันรู้โดยค่าเริ่มต้นที่==เรียกวิธีการequal?ซึ่งผลตอบแทนจริงเมื่อตัวถูกดำเนินการทั้งสองอ้างถึงวัตถุเดียวกัน

===โดยค่าเริ่มต้นยังสาย==ที่โทรequal?... ไม่เป็นไรดังนั้นหากทั้งสามวิธีการไม่ได้แทนที่แล้วผมคิดว่า ===, ==และequal?ทำสิ่งเดียวกัน?

มาถึงeql?แล้ว สิ่งนี้ทำอะไร (โดยค่าเริ่มต้น) มันเรียกแฮช / ไอดีของตัวถูกดำเนินการหรือไม่?

ทำไมทับทิมถึงมีเครื่องหมายความเสมอภาคมากมาย? พวกเขาควรจะแตกต่างกันในความหมาย?


ฉันเพิ่งเริ่มต้นคณะกรรมการและมีผลต่อไปซึ่งขัดแย้งกับคุณ ... ทั้งหมดนี้ 3 เป็นจริง: "a" == "a", และ"a" === "a" "a".eql? "a"แต่นี่เป็นเท็จ: "a".equal? "a"(เหมืองทับทิม 1.9.2-p180)
PeterWong

7
@Peter: นั่นเป็นเพราะสตริงแทนที่ผู้ประกอบการที่เท่าเทียมกันทั้งหมด พยายามใช้a = Object.new; b = Object.newแล้วทั้งหมด==, ===, .equal?, .eql?จะกลับมาtrueสำหรับaVS aและเท็จสำหรับVSa b
Nemo157

คำตอบ:


785

ฉันจะอ้างอิงเอกสาร Objectอย่างมากที่นี่เพราะฉันคิดว่ามันมีคำอธิบายที่ดี ผมแนะนำให้คุณอ่านมันและยังเอกสารสำหรับวิธีการเหล่านี้ที่พวกเขากำลังถูกแทนที่ในชั้นเรียนอื่น ๆ เช่นString

หมายเหตุด้านข้าง: หากคุณต้องการลองสิ่งเหล่านี้ด้วยตัวคุณเองบนวัตถุที่แตกต่างให้ใช้สิ่งต่อไปนี้:

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}

== - "ความเท่าเทียมกัน" ทั่วไป

ที่ระดับออบเจคต์==จะคืนค่าเป็นจริงหากobjและotherเป็นวัตถุเดียวกันเท่านั้น โดยทั่วไปแล้ววิธีการนี้จะถูกแทนที่ในคลาสที่สืบทอดเพื่อให้ความหมายเฉพาะคลาส

นี่คือการเปรียบเทียบที่พบบ่อยที่สุดและเป็นสถานที่พื้นฐานที่สุดที่คุณ (ในฐานะผู้เขียนชั้นเรียน) จะต้องตัดสินใจว่าวัตถุสองรายการนั้น "เท่ากัน" หรือไม่

=== - ความเท่าเทียมกันของคดี

สำหรับคลาส Object ให้ผลเหมือนกับการโทร#==แต่โดยทั่วไปจะถูกแทนที่โดยผู้สืบทอดเพื่อให้ความหมายที่มีความหมายในคำสั่ง case

มันมีประโยชน์อย่างเหลือเชื่อ ตัวอย่างของสิ่งต่าง ๆ ที่มี===การใช้งานที่น่าสนใจ:

  • พิสัย
  • regex
  • Proc (ใน Ruby 1.9)

ดังนั้นคุณสามารถทำสิ่งต่าง ๆ เช่น:

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

ดูคำตอบของฉันที่นี่เพื่อดูตัวอย่างว่าcase+ Regexสามารถสร้างรหัสให้สะอาดขึ้นได้อย่างไร และแน่นอนโดยการให้===การใช้งานของคุณเองคุณสามารถรับcaseความหมายที่กำหนดเอง

eql?- Hashความเท่าเทียมกัน

eql?วิธีการส่งกลับจริงถ้าobjและotherอ้างถึงคีย์กัญชาเดียวกัน สิ่งนี้ถูกใช้โดยHashการทดสอบสมาชิกเพื่อความเท่าเทียมกัน สำหรับวัตถุของคลาสObject, ตรงกันกับeql? ==คลาสย่อยตามปกติจะดำเนินการตามประเพณีนี้โดยใช้นามแฝงeql?กับ==วิธีการแทนที่แต่มีข้อยกเว้น Numericประเภทเช่นดำเนินการแปลงประเภทข้าม==แต่ไม่ข้ามeql?ดังนั้น:

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

ดังนั้นคุณมีอิสระที่จะแทนที่สิ่งนี้สำหรับการใช้งานของคุณเองหรือคุณสามารถแทนที่==และใช้alias :eql? :==เพื่อให้ทั้งสองวิธีทำงานในลักษณะเดียวกัน

equal? - การเปรียบเทียบเอกลักษณ์

ซึ่งแตกต่างจาก==ที่equal?วิธีการที่ไม่ควรจะถูกแทนที่โดย subclasses: จะใช้ในการตรวจสอบตัวตนของวัตถุ (นั่นคือa.equal?(b)IFF aเป็นวัตถุเช่นเดียวb)

นี่เป็นการเปรียบเทียบตัวชี้อย่างมีประสิทธิภาพ


32
ตามที่ฉันเข้าใจจากคำตอบของคุณความเข้มงวดคือ: เท่ากัน? <eql <== <=== โดยปกติคุณใช้ == เพื่อวัตถุประสงค์ที่หลวมคุณใช้ === สำหรับสถานการณ์ที่เข้มงวดคุณใช้ eql? และสำหรับตัวตนที่สมบูรณ์คุณใช้เท่ากันหรือไม่
sawa

21
ความคิดของความเข้มงวดการบังคับใช้ไม่ได้หรือแม้กระทั่งปัญหาในเอกสารนี้มันเกิดขึ้นเพียงเพื่อที่จับในลักษณะที่เข้มงวดกว่าNumeric ==มันขึ้นอยู่กับผู้แต่งของชั้นเรียนจริงๆ ===มีการใช้งานบ่อยครั้งนอกcaseงบ
jtbandes

4
== คือความเท่าเทียมกันในแง่ของขนาดใหญ่ / เล็กเกินไป นั่นคือถ้าคุณใส่ Comparable แล้วมันจะถูกกำหนดในรูปของ <=> return 0 นี่คือสาเหตุที่ 1 == 1.0 คืนค่าจริง
apeiros

5
@sawa ฉันมักจะคิดว่า===เป็นความหมายของ "การแข่งขัน" (คร่าว ๆ ) เช่นเดียวกับใน "regexp จับคู่สตริง" หรือ "จับคู่ช่วง (รวม) ตัวเลข"
เคลวิน

7
เรื่องสนุก: เอกสารอย่างเป็นทางการเชื่อมโยงกับคำตอบนี้แล้ว (ดูruby-doc.org/core-2.1.5/… )
Mark Amery

46

ฉันชอบคำตอบ jtbandes แต่เนื่องจากมันค่อนข้างยาวฉันจะเพิ่มคำตอบแบบกระชับของตัวเอง:

==, ===, eql?,equal?
4 comparators คือ 4 วิธีในการเปรียบเทียบ 2 วัตถุใน Ruby
เช่นเดียวกับใน Ruby ตัวเปรียบเทียบทั้งหมด (และตัวดำเนินการส่วนใหญ่) เป็นวิธีการเรียกใช้จริงคุณสามารถเปลี่ยนเขียนทับและกำหนดความหมายของวิธีการเปรียบเทียบเหล่านี้ด้วยตัวคุณเอง อย่างไรก็ตามมันเป็นสิ่งสำคัญที่จะต้องเข้าใจเมื่อภาษาภายในของรูบี้ใช้ตัวเปรียบเทียบแบบใด:

==(การเปรียบเทียบค่า)
Ruby ใช้: == ทุกที่เพื่อเปรียบเทียบค่าของ 2 วัตถุเช่น กัญชาค่า:

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

===(การเปรียบเทียบตัวพิมพ์ใหญ่)
Ruby ใช้: === ในกรณี / เมื่อสร้าง ข้อมูลโค้ดต่อไปนี้เหมือนกันตามหลักเหตุผล:

case foo
  when bar;  p 'do something'
end

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

eql?(การเปรียบเทียบแฮชคีย์)
Ruby ใช้: eql? (ใช้ร่วมกับแฮชเมธอด) เพื่อเปรียบเทียบคีย์แฮช ในชั้นเรียนส่วนใหญ่: eql? เหมือนกันกับ: ==
ความรู้เกี่ยวกับ: eql? เป็นสิ่งสำคัญเท่านั้นเมื่อคุณต้องการสร้างคลาสพิเศษของคุณเอง:

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

หมายเหตุ: ชุด Ruby-class ที่ใช้กันทั่วไปนั้นต้องอาศัยการเปรียบเทียบ Hash-key-

equal?(การเปรียบเทียบเอกลักษณ์วัตถุ)
Ruby ใช้: เท่ากับหรือไม่ เพื่อตรวจสอบว่าวัตถุสองอย่างเหมือนกันหรือไม่ เมธอดนี้ (ของคลาส BasicObject) ไม่ควรถูกเขียนทับ

obj = obj2 = 'a'
obj.equal? obj2       # => true
obj.equal? obj.dup    # => false

30
มันเป็นคำตอบที่ดี แต่เกือบจะนานเท่าที่ jtbandes :)
odigity

2
@ ชุมชนประมาณ 70% ตราบใด ฉันคิดว่าหลายสิ่งหลายอย่างที่จะใช้จ่าย 30% ใน
Cary Swoveland

ฉันคิดว่าตัวอย่างeql?ที่ทำให้เข้าใจผิดมาก eql?คือการเปรียบเทียบความเสมอภาคที่สอดคล้องกับวิธีการกัญชาคำนวณคือรับประกันว่าa.eql?(b) a.hash == b.hashมันไม่เพียงเปรียบเทียบรหัสแฮช
Andrey Tarantsov

การเปรียบเทียบเคสนั้นเทียบเท่ากับbar === fooและไม่จริงfoo === barเหรอ? ฉันหวังว่าหลังนี้จะถูกต้องและเป็นสิ่งสำคัญเนื่องจากคอมไพเลอร์เรียกทางซ้ายมือ: === `'
Alexis Wilke

เท่าที่ฉันรู้ก็คือbar === foo: Ruby ใช้ค่าเคสที่ด้านซ้ายมือและตัวแปรเคสที่อยู่ทางขวามือ สิ่งนี้อาจเกี่ยวข้องกับการหลีกเลี่ยง NPE (ข้อยกเว้นตัวชี้ Null)
Andreas Rayo Kniep

34

ตัวดำเนินการความเสมอภาค: == และ! =

ตัวดำเนินการ == หรือที่รู้จักกันว่าความเท่าเทียมกันหรือเท่ากันสองเท่าจะส่งกลับค่าจริงถ้าวัตถุทั้งสองมีค่าเท่ากันและเป็นเท็จหากไม่มี

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

ตัวดำเนินการ! = หรือที่รู้จักกันว่าความไม่เท่าเทียมกันนั้นตรงกันข้ามกับ == มันจะกลับมาจริงถ้าวัตถุทั้งสองไม่เท่ากันและเท็จถ้าพวกเขาเท่ากัน

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

โปรดทราบว่าสองอาร์เรย์ที่มีองค์ประกอบเดียวกันในลำดับที่แตกต่างกันจะไม่เท่ากันตัวอักษรตัวพิมพ์ใหญ่และตัวพิมพ์เล็กของตัวอักษรเดียวกันจะไม่เท่ากันเป็นต้น

เมื่อเปรียบเทียบจำนวนประเภทต่าง ๆ (เช่นจำนวนเต็มและจำนวนลอย) หากค่าตัวเลขเหมือนกัน == จะส่งกลับค่าจริง

2 == 2.0 # Output: => true

เท่ากัน?

ไม่เหมือนกับตัวดำเนินการ == ซึ่งทดสอบว่าตัวถูกดำเนินการทั้งสองเท่ากันหรือไม่วิธีการที่เท่ากันจะตรวจสอบว่าตัวถูกดำเนินการทั้งสองอ้างถึงวัตถุเดียวกันหรือไม่ นี่คือรูปแบบที่เข้มงวดที่สุดของความเท่าเทียมกันในทับทิม

ตัวอย่าง: a = "zen" b = "zen"

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

a.equal? b  # Output: => false

ในตัวอย่างข้างต้นเรามีสองสตริงที่มีค่าเท่ากัน อย่างไรก็ตามมันเป็นวัตถุสองชิ้นที่แตกต่างกันโดยมี ID วัตถุต่างกัน ดังนั้นที่เท่ากัน? วิธีการจะกลับเท็จ

ลองอีกครั้งเฉพาะเวลานี้ b จะเป็นการอ้างอิงถึง ขอให้สังเกตว่า ID วัตถุเหมือนกันสำหรับตัวแปรทั้งสองเนื่องจากพวกเขาชี้ไปที่วัตถุเดียวกัน

a = "zen"
b = a

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

a.equal? b  # Output: => true

EQL?

ในชั้น Hash, eql? วิธีใช้สำหรับทดสอบคีย์เพื่อความเท่าเทียมกัน พื้นหลังบางอย่างจำเป็นต้องอธิบายเรื่องนี้ ในบริบททั่วไปของการคำนวณฟังก์ชันแฮชจะใช้สตริง (หรือไฟล์) ขนาดใดก็ได้และสร้างสตริงหรือจำนวนเต็มขนาดคงที่เรียกว่าแฮชโค้ดซึ่งโดยทั่วไปจะเรียกว่าแฮชเท่านั้น ประเภทแฮชโค้ดที่ใช้กันทั่วไปบางประเภทคือ MD5, SHA-1 และ CRC พวกมันถูกใช้ในอัลกอริธึมการเข้ารหัสการทำดัชนีฐานข้อมูลการตรวจสอบความสมบูรณ์ของไฟล์ ฯลฯ ภาษาการเขียนโปรแกรมบางอย่างเช่น Ruby ให้ประเภทของคอลเลกชันที่เรียกว่าตารางแฮช ตารางแฮชคือชุดพจนานุกรมที่เก็บข้อมูลเป็นคู่ประกอบด้วยคีย์เฉพาะและค่าที่เกี่ยวข้อง ภายใต้ประทุนคีย์เหล่านั้นจะถูกเก็บไว้เป็นแฮชโค้ด ตารางแฮชมักจะเรียกว่าเป็นเพียงแค่แฮช สังเกตว่าคำว่า hashcan อ้างอิงถึง hashcode หรือตาราง hash อย่างไร

Ruby นำเสนอวิธีการในตัวที่เรียกว่าแฮชสำหรับสร้างแฮชโค้ด ในตัวอย่างด้านล่างมันต้องใช้สตริงและส่งกลับ hashcode ขอให้สังเกตว่าสตริงที่มีค่าเดียวกันจะมีแฮชโค้ดที่เหมือนกันแม้ว่าจะเป็นวัตถุที่แตกต่างกัน (ด้วย ID วัตถุที่แตกต่างกัน)

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

วิธีการแฮชนำมาใช้ในโมดูลเคอร์เนลซึ่งรวมอยู่ในคลาสวัตถุซึ่งเป็นรูทเริ่มต้นของวัตถุทับทิมทั้งหมด บางคลาสเช่น Symbol และ Integer ใช้การเริ่มต้นใช้งานส่วนอื่น ๆ เช่น String และ Hash จะมีการใช้งานของตัวเอง

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 เมื่อเราเก็บบางสิ่งในแฮช (คอลเลกชัน) วัตถุที่ให้เป็นคีย์ (เช่นสตริงหรือสัญลักษณ์) จะถูกแปลงเป็นและเก็บเป็นแฮชโค้ด ต่อมาเมื่อดึงองค์ประกอบจากแฮช (คอลเลกชัน) เราให้วัตถุเป็นคีย์ซึ่งจะถูกแปลงเป็นแฮชโค้ดและเปรียบเทียบกับคีย์ที่มีอยู่ หากมีการแข่งขันค่าของรายการที่สอดคล้องกันจะถูกส่งกลับ ทำการเปรียบเทียบโดยใช้ eql หรือไม่ วิธีการภายใต้ประทุน

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

ในกรณีส่วนใหญ่ eql? วิธีการทำงานคล้ายกับวิธี == อย่างไรก็ตามมีข้อยกเว้นเล็กน้อย ตัวอย่างเช่น eql? ไม่ทำการแปลงชนิดโดยนัยเมื่อเปรียบเทียบจำนวนเต็มกับทศนิยม

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

ตัวดำเนินการความเสมอภาคของคดี: ===

หลายคลาสในตัวของรูบี้เช่น String, Range, และ Regexp นำเสนอการใช้งานของตัวเองของโอเปอเรเตอร์ === ซึ่งรู้จักกันในชื่อ case-equality, triple เท่ากับหรือ threequals เนื่องจากมันมีการใช้งานที่แตกต่างกันในแต่ละชั้นเรียนมันจะทำงานแตกต่างกันไปขึ้นอยู่กับประเภทของวัตถุที่ถูกเรียกใช้ โดยทั่วไปแล้วจะส่งกลับค่าจริงหากวัตถุทางด้านขวา "เป็นของ" หรือ "เป็นสมาชิกของ" วัตถุทางด้านซ้าย ตัวอย่างเช่นมันสามารถใช้ในการทดสอบว่าวัตถุเป็นตัวอย่างของการเรียน (หรือหนึ่งในคลาสย่อยของมัน)

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

ผลลัพธ์เดียวกันสามารถทำได้ด้วยวิธีอื่น ๆ ซึ่งอาจเหมาะสมที่สุดสำหรับงาน โดยปกติแล้วการเขียนโค้ดที่อ่านง่ายโดยชัดเจนที่สุดเท่าที่จะทำได้โดยไม่ต้องเสียสละประสิทธิภาพและความรัดกุม

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

ขอให้สังเกตตัวอย่างสุดท้ายที่ส่งคืนเท็จเนื่องจากจำนวนเต็มเช่น 2 เป็นอินสแตนซ์ของคลาส Fixnum ซึ่งเป็นคลาสย่อยของคลาส Integer ===, is_a? และ instance_of? วิธีการส่งกลับจริงถ้าวัตถุเป็นตัวอย่างของการเรียนที่กำหนดหรือคลาสย่อยใด ๆ เมธอด instance_of นั้นเข้มงวดและจะคืนค่าเป็นจริงถ้าอ็อบเจ็กต์เป็นอินสแตนซ์ของคลาสที่แน่นอนไม่ใช่คลาสย่อย

is_a และ kind_of? วิธีการที่จะดำเนินการในโมดูลเคอร์เนลซึ่งถูกผสมในคลาสวัตถุ ทั้งสองเป็นนามแฝงกับวิธีการเดียวกัน ตรวจสอบกันเลย:

Kernel.instance_method (: kind_of?) == Kernel.instance_method (: is_a?) # ผลลัพธ์: => จริง

การใช้งานช่วง ===

เมื่อผู้ประกอบการ === ถูกเรียกบนวัตถุช่วงมันจะส่งกลับจริงถ้าค่าทางด้านขวาตกอยู่ในช่วงทางด้านซ้าย

(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

โปรดจำไว้ว่าตัวดำเนินการ === จะเรียกใช้เมธอด === ของวัตถุทางซ้าย ดังนั้น (1..4) === 3 จึงเท่ากับ (1..4) === 3. กล่าวอีกนัยหนึ่งคลาสของตัวถูกดำเนินการทางซ้ายจะกำหนดว่าการใช้งานวิธี === จะเป็นอย่างไร เรียกดังนั้นตำแหน่งตัวถูกดำเนินการไม่สามารถใช้แทนกันได้

การใช้ Regexp ของ ===

ผลตอบแทนจริงถ้าสตริงด้านขวาตรงกับการแสดงออกปกติทางด้านซ้าย / zen / === "ฝึกฝน zazen วันนี้" # เอาท์พุท: => true # เหมือนกับ "ฝึก zazen วันนี้" = ~ / zen /

การใช้งานโดยนัยของโอเปอเรเตอร์ === สำหรับคำสั่ง case / when

ผู้ประกอบการนี้ยังใช้ภายใต้ประทุนในกรณีที่ / เมื่องบ นั่นคือการใช้งานที่พบบ่อยที่สุด

minutes = 15

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

# Output: match

ในตัวอย่างด้านบนหาก Ruby ใช้ตัวดำเนินการเท่ากับสองเท่าโดยนัย (==) ช่วง 10..20 จะไม่ถูกพิจารณาว่าเท่ากับจำนวนเต็มเช่น 15 พวกเขาจับคู่เพราะตัวดำเนินการเท่ากับสามตัว (===) คือ ใช้โดยนัยในทุกกรณี / เมื่อมีคำสั่ง โค้ดในตัวอย่างด้านบนเทียบเท่ากับ:

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

ตัวดำเนินการจับคู่รูปแบบ: = ~ และ! ~

ตัวดำเนินการ = ~ (เท่ากับ-tilde) และ! ~ (bang-tilde) ใช้เพื่อจับคู่สตริงและสัญลักษณ์กับรูปแบบ regex

การใช้งานเมธอด = ~ ในคลาส String และ Symbol ต้องการนิพจน์ทั่วไป (อินสแตนซ์ของคลาส Regexp) เป็นอาร์กิวเมนต์

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

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

การใช้งานในคลาส Regexp คาดว่าสตริงหรือสัญลักษณ์เป็นอาร์กิวเมนต์

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

ในการประยุกต์ใช้ทั้งหมดเมื่อสตริงหรือสัญลักษณ์ตรงกับรูปแบบ Regexp มันจะส่งกลับจำนวนเต็มซึ่งเป็นตำแหน่ง (ดัชนี) ของการแข่งขัน หากไม่มีการจับคู่ก็จะส่งกลับศูนย์ โปรดจำไว้ว่าใน Ruby ค่าจำนวนเต็มใด ๆ คือ "truey" และ nil คือ "falsy" ดังนั้นตัวดำเนินการ = ~ สามารถใช้ในถ้า statement และตัวดำเนินการที่ประกอบไปด้วยสามส่วน

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

โอเปอเรเตอร์การจับคู่รูปแบบยังมีประโยชน์สำหรับการเขียนให้สั้นลงหากคำสั่ง ตัวอย่าง:

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

ตัวดำเนินการ! ~ อยู่ตรงข้ามกับ = ~ มันจะส่งกลับค่าจริงเมื่อไม่มีการจับคู่และเท็จถ้ามีการแข่งขัน

ข้อมูลเพิ่มเติมสามารถดูได้ที่โพสต์บล็อกนี้


6
ฉันพบว่านี่เป็นคำตอบที่ดีกว่าคำตอบที่ยอมรับในขณะนี้เพราะมันเป็นตัวอย่างที่ดีและไม่ชัดเจนเกี่ยวกับความแตกต่างของความเท่าเทียมกันและทำไมพวกเขาถึงอยู่ที่ไหน / ที่ไหนที่พวกเขาใช้
Qqwy

1
คำตอบที่มีรายละเอียดมาก แต่ใน irb ของฉัน (ruby v 2.2.1) :zen === "zen"กลับเท็จ
Mike R

@MikeR ขอบคุณที่แจ้งให้เราทราบ ฉันแก้ไขคำตอบแล้ว
BrunoFacca

ฉันคิดว่าคุณหมายถึง type_of? "ขอให้สังเกตตัวอย่างสุดท้ายที่ส่งคืนเท็จเนื่องจากจำนวนเต็มเช่น 2 เป็นอินสแตนซ์ของคลาส Fixnum ซึ่งเป็นคลาสย่อยของคลาสจำนวนเต็ม ===, is_a? และ instance_of? (TYPE_OF?)"?
user1883793

1
ฉันรักคำตอบนี้ ขอบคุณ
Abdullah Fadhel

9

Ruby เปิดเผยวิธีการต่าง ๆ สำหรับการจัดการความเท่าเทียมกัน:

a.equal?(b) # object identity - a and b refer to the same object

a.eql?(b) # object equivalence - a and b have the same value

a == b # object equivalence - a and b have the same value with type conversion.

อ่านต่อโดยคลิกที่ลิงก์ด้านล่างมันทำให้ฉันมีความเข้าใจสรุปที่ชัดเจน

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

หวังว่าจะช่วยผู้อื่น


8

=== # --- กรณีที่เท่าเทียมกัน

== # --- ความเท่าเทียมกันทั่วไป

ทั้งสองทำงานคล้ายกัน แต่ "===" แม้ทำข้อความสั่งเคส

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

นี่คือความแตกต่าง

String === "test"   #=> true
String == "test"  #=> false

3
พวกเขาไม่ได้ทำงานในทำนองเดียวกันแม้ว่าจะมีแนวโน้มที่จะเป็นจริงที่ว่าเมื่อแล้วa==b a===bแต่a===bมีพลังมากขึ้น ===ไม่สมมาตรและa===bหมายถึงสิ่งที่แตกต่างจากการให้อยู่คนเดียวb===a a==b
mwfearnley

8

ฉันต้องการขยาย===ผู้ประกอบการ

=== ไม่ได้เป็นผู้ประกอบการความเท่าเทียมกัน!

ไม่.

มาจุดนั้นกันจริงๆ

คุณอาจคุ้นเคยกับ===การเป็นผู้ดำเนินการความเท่าเทียมกันใน Javascript และ PHP แต่นี่ไม่ใช่ตัวดำเนินการเท่าเทียมกันใน Ruby และมีความหมายที่แตกต่างกันโดยพื้นฐาน

แล้วจะ===ทำอย่างไรดี?

=== เป็นผู้ประกอบการจับคู่รูปแบบ!

  • === จับคู่นิพจน์ทั่วไป
  • === ตรวจสอบสมาชิกช่วง
  • === ตรวจสอบเป็นตัวอย่างของชั้นเรียน
  • === เรียกการแสดงออกแลมบ์ดา
  • === บางครั้งตรวจสอบความเท่าเทียมกัน แต่ส่วนใหญ่ไม่ได้

ดังนั้นความบ้าคลั่งนี้จึงสมเหตุสมผลได้อย่างไร

  • Enumerable#grepใช้===ภายใน
  • case when งบใช้ ===ภายใน
  • สนุกจริงrescueใช้===ภายใน

นั่นคือเหตุผลที่คุณสามารถใช้นิพจน์ปกติและคลาสและช่วงและแม้แต่แลมบ์ดานิพจน์ใน case whenคำสั่ง

ตัวอย่างบางส่วน

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

ตัวอย่างทั้งหมดเหล่านี้ทำงานด้วยpattern === valueเช่นกันเช่นเดียวกับ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]

-8

ฉันเขียนข้อสอบง่าย ๆ ข้างต้น

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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.