ความแตกต่างระหว่าง == และ. equals ใน Scala คืออะไร


144

ความแตกต่างระหว่าง==และ.equals()ในสกาล่าคืออะไรและเมื่อใดควรใช้อันไหน

การใช้งานเหมือนกับใน Java หรือไม่?

แก้ไข: AnyValคำถามที่เกี่ยวข้องกับการเจรจาเกี่ยวกับกรณีที่เฉพาะเจาะจงของ Anyกรณีทั่วไปมากขึ้นคือ



@Ben ฉันคิดว่าคำถามอื่นควรทำเครื่องหมายว่าซ้ำกันโดยพิจารณาจากวันที่ถาม นอกจากนี้ฉันรู้สึกว่าคำถามสองข้อนั้นแตกต่างกัน
Jus12

คำตอบ:


201

ปกติคุณจะใช้==มันจะนำไปสู่การequalsยกเว้นว่าจะปฏิบัติต่อnullอย่างถูกต้อง ความเสมอภาคอ้างอิง (ไม่ค่อยได้ใช้) eqเป็น


12
ใช้กับห้องสมุด Java ด้วยหรือไม่
Jus12

20
มันทำ ตัวอย่างเช่นใหม่ java.util.ArrayList [Int] () == ใหม่ java.util.ArrayList [Int] () ตามที่เท่ากับ On ArrayList คือความเท่าเทียมกันของเนื้อหา
Didier Dupont

5
นอกจากนี้ยังมีพฤติกรรมที่แปลก ๆ รอบ Int และ Long และ == เมื่อเทียบกับ. equals () จำนวนเดียวกันกับ Int และ As Long return true สำหรับ == แต่ false สำหรับเท่ากับ ดังนั้น == ไม่ได้กำหนดเส้นทางให้เท่ากับเสมอ
Harold L

24
น่าสนใจยิ่งขึ้นทั้งสอง3 == BigInt(3)และBigInt(3) == 3เป็นจริง แต่3.equals(BigInt(3))เป็นเท็จในขณะที่BigInt(3).equals(3)เป็นจริง ==ดังนั้นชอบใช้ หลีกเลี่ยงการใช้equals()ในสกาล่า ฉันคิดว่า==การแปลงโดยนัยทำได้ดี แต่equals()ทำไม่ได้
Naetmul

เหตุใดจึงnew java.lang.Integer(1) == new java.lang.Double(1.0)เป็นจริงในขณะที่new java.lang.Integer(1) equals new java.lang.Double(1.0)เป็นเท็จ
Eastsun

34

==เป็นวิธีสุดท้ายและการโทร.equalsซึ่งไม่ใช่วิธีสุดท้าย

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


29

TL; DR

  • แทนที่ equalsวิธีการเพื่อเปรียบเทียบเนื้อหาของแต่ละอินสแตนซ์ นี่เป็นequalsวิธีเดียวกับที่ใช้ใน Java
  • ใช้ ==โอเปอเรเตอร์เพื่อเปรียบเทียบโดยไม่ต้องกังวลกับnullการอ้างอิง
  • ใช้eqวิธีการตรวจสอบว่าข้อโต้แย้งทั้งสองตรงอ้างอิงเดียวกัน ไม่แนะนำให้ใช้จนกว่าคุณจะเข้าใจวิธีการทำงานและมักequalsจะทำงานในสิ่งที่คุณต้องการแทน และให้แน่ใจว่าจะใช้เฉพาะกับAnyRefข้อโต้แย้งไม่ใช่เพียงAny

หมายเหตุ: ในกรณีของequalsเช่นเดียวกับใน Java มันอาจไม่ส่งกลับผลลัพธ์เดียวกันถ้าคุณเปลี่ยนอาร์กิวเมนต์เช่น1.equals(BigInt(1))จะกลับfalseที่ผกผันจะกลับมาtrueที่ผกผันจะกลับมานี่เป็นเพราะการตรวจสอบการใช้งานแต่ละประเภทเท่านั้น หมายเลขดั้งเดิมไม่ตรวจสอบว่าอาร์กิวเมนต์ที่สองเป็นแบบNumberหรือBigIntแบบ แต่มีประเภทแบบดั้งเดิมเท่านั้น

รายละเอียด

AnyRef.equals(Any)วิธีการเป็นหนึ่งแทนที่โดย subclasses วิธีการจากข้อกำหนดของจาวาที่มาถึง Scala ด้วย หากใช้กับอินสแตนซ์ที่ไม่ได้ทำกล่องจะถูกเรียกให้เรียกสิ่งนี้ (แม้ว่าจะซ่อนอยู่ใน Scala แต่จะชัดเจนกว่าใน Java ด้วยint->Integer ) การใช้งานเริ่มต้นเพียงเปรียบเทียบการอ้างอิง (เช่นใน Java)

Any.==(Any)วิธีการเปรียบเทียบสองวัตถุและช่วยให้การโต้แย้งใดอย่างหนึ่งเพื่อเป็นโมฆะ (เช่นถ้าเรียกวิธีคงมีสองกรณี) มันเปรียบเทียบว่าทั้งคู่เป็นแบบnullนั้นequals(Any)หรือเปล่าแล้วมันจะเรียกเมธอดบนอินสแตนซ์ของกล่อง

AnyRef.eq(AnyRef)วิธีการเปรียบเทียบเพียงการอ้างอิงที่เป็นที่อินสแตนซ์ตั้งอยู่ในความทรงจำ ไม่มีมวยโดยนัยสำหรับวิธีนี้

ตัวอย่าง

  • 1 equals 2จะกลับมาfalseตามที่มันเปลี่ยนเส้นทางไปInteger.equals(...)
  • 1 == 2จะกลับมาfalseตามที่มันเปลี่ยนเส้นทางไปInteger.equals(...)
  • 1 eq 2 จะไม่คอมไพล์เนื่องจากต้องการอาร์กิวเมนต์ทั้งสองประเภท AnyRef
  • new ArrayList() equals new ArrayList()จะกลับมาtrueตามที่ตรวจสอบเนื้อหา
  • new ArrayList() == new ArrayList()จะกลับมาtrueตามที่มันเปลี่ยนเส้นทางไปequals(...)
  • new ArrayList() eq new ArrayList()จะส่งคืนfalseเนื่องจากอาร์กิวเมนต์ทั้งสองเป็นอินสแตนซ์ต่างกัน
  • foo equals fooจะกลับมาtrueเว้นแต่fooจะเป็นnullแล้วจะส่งNullPointerException
  • foo == fooจะกลับมาtrueแม้ว่าfooจะเป็นnull
  • foo eq fooจะกลับมาtrueเนื่องจากข้อโต้แย้งทั้งสองเชื่อมโยงไปยังการอ้างอิงเดียวกัน

6

มีความแตกต่างที่น่าสนใจระหว่าง==และequalsสำหรับFloatและDoubleประเภท: พวกเขาปฏิบัติNaNแตกต่างกัน:

scala> Double.NaN == Double.NaN
res3: Boolean = false

scala> Double.NaN equals Double.NaN
res4: Boolean = true

แก้ไข:ตามที่ถูกชี้ให้เห็นในความคิดเห็น - "สิ่งนี้ยังเกิดขึ้นใน Java" - ขึ้นอยู่กับสิ่งนี้คือ:

public static void main(final String... args) {
    final double unboxedNaN = Double.NaN;
    final Double boxedNaN = Double.valueOf(Double.NaN);

    System.out.println(unboxedNaN == unboxedNaN);
    System.out.println(boxedNaN == boxedNaN);
    System.out.println(boxedNaN.equals(boxedNaN));
}

สิ่งนี้จะพิมพ์

false
true
true

ดังนั้นunboxedNanอัตราผลตอบแทนfalseเมื่อเทียบกับความเท่าเทียมกันเพราะนี่คือวิธีที่ตัวเลขทศนิยม IEEE กำหนดและสิ่งนี้ควรเกิดขึ้นจริงในทุกภาษาการเขียนโปรแกรม (แม้ว่ามันจะยุ่งกับความคิดของตัวตน)

NaN ชนิดบรรจุกล่องให้ผลจริงสำหรับการเปรียบเทียบโดยใช้ ==ใน Java เนื่องจากเรากำลังเปรียบเทียบการอ้างอิงวัตถุ

ฉันไม่ได้มีคำอธิบายสำหรับequalsกรณี IMHO มันควรจะทำตัวเหมือนกัน==กับค่าสองกล่องที่ไม่ได้ทำ แต่มันไม่มี

สกาลาที่แปลไปยังสกาลานั้นมีความซับซ้อนมากกว่าเล็กน้อยเนื่องจากสกาลามีการรวมกันของวัตถุดั้งเดิมและวัตถุAnyเป็นหนึ่งเดียว ดังนั้นสกาล่า==ชัดเดือดลงไปเปรียบเทียบดั้งเดิมNaNค่า แต่equalsใช้อย่างใดอย่างหนึ่งที่กำหนดไว้ในค่าคู่บรรจุกล่อง (มีเป็นจำนวนมากของเวทมนตร์แปลงนัยที่เกิดขึ้นและมีสิ่ง pimped บนคู่ผสมโดยRichDouble)

หากคุณต้องการตรวจสอบว่ามีการNaNใช้งานจริงหรือไม่isNaN:


และสิ่งนี้ก็เกิดขึ้นใน Java!
Iwan Satria

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