Perbedaan antara == dan ===


299

Di swift tampaknya ada dua operator kesetaraan: ganda sama dengan ( ==) dan tiga sama dengan ( ===), apa perbedaan antara keduanya?

Jawaban:


149

Pendeknya:

== Operator memeriksa apakah nilai instance mereka sama, "equal to"

=== Operator memeriksa apakah referensi menunjukkan instance yang sama, "identical to"

Jawaban panjang:

Kelas adalah tipe referensi, dimungkinkan untuk konstanta berganda dan variabel untuk merujuk ke instance tunggal yang sama dari kelas di belakang layar. Referensi kelas tetap di Run Time Stack (RTS) dan instansnya tetap di area tumpukan Memori. Ketika Anda mengontrol kesetaraan dengan ==itu berarti jika instance mereka sama satu sama lain. Tidak harus sama untuk menjadi sama. Untuk ini, Anda perlu memberikan kriteria kesetaraan untuk kelas khusus Anda. Secara default, kelas dan struktur khusus tidak menerima implementasi default dari operator ekivalen, yang dikenal sebagai operator "sama dengan" ==dan operator "tidak sama dengan" !=. Untuk melakukan ini, kelas khusus Anda harus menyesuaikan Equatableprotokol dan static func == (lhs:, rhs:) -> Boolfungsinya

Mari kita lihat contohnya:

class Person : Equatable {
    let ssn: Int
    let name: String

    init(ssn: Int, name: String) {
        self.ssn = ssn
        self.name = name
    }

    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.ssn == rhs.ssn
    }
}

P.S.: Karena ssn (nomor jaminan sosial) adalah nomor unik, Anda tidak perlu membandingkan apakah namanya sama atau tidak.

let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")

if person1 == person2 {
   print("the two instances are equal!")
}

Walaupun referensi person1 dan person2 menunjukkan dua instance berbeda di area Heap, instance mereka sama karena angka ssnnya sama. Jadi hasilnya akanthe two instance are equal!

if person1 === person2 {
   //It does not enter here
} else {
   print("the two instances are not identical!")
}

===Operator memeriksa apakah referensi menunjuk ke instance yang sama "identical to",. Karena person1 dan person2 memiliki dua contoh berbeda di area Heap, mereka tidak identik dan hasilnyathe two instance are not identical!

let person3 = person1

P.S: Kelas adalah tipe referensi dan referensi person1 disalin ke person3 dengan operasi penugasan ini, sehingga kedua referensi menunjuk contoh yang sama di area Heap.

if person3 === person1 {
   print("the two instances are identical!")
}

Mereka identik dan hasilnya akan seperti itu the two instances are identical!


248

!==dan ===merupakan operator identitas dan digunakan untuk menentukan apakah dua objek memiliki referensi yang sama.

Swift juga menyediakan dua operator identitas (=== dan! ==), yang Anda gunakan untuk menguji apakah dua referensi objek keduanya merujuk ke instance objek yang sama.

Kutipan dari: Apple Inc. “Bahasa Pemrograman Swift.” iBooks.https://itun.es/us/jEUH0.l


49
Ya. Berasal dari ObjC, ==adalah isEqual:, atau kesetaraan semantik yang ditentukan kelas. ===dalam Swift adalah ==dalam (Obj) C - pointer kesetaraan, atau identitas objek.
rickster

Nilai @rickster Dont 'juga memiliki lokasi memori? Saya akhirnya mereka berada di suatu tempat di memori. Tidak bisakah kamu membandingkannya? Atau apakah lokasi memori mereka tidak menawarkan nilai berarti ?
Sayang

2
Setidaknya ada dua cara untuk berpikir tentang bagaimana bahasa mendefinisikan tipe nilai vs memori. Salah satunya adalah bahwa setiap pengikatan ( varatau let) nama ke nilai adalah salinan unik - jadi tidak ada artinya untuk membuat pointer karena nilai yang Anda buat pointer adalah nilai yang berbeda dari yang Anda buat pertama kali. Lain adalah bahwa definisi Swift tentang semantik nilai mengabstraksi penyimpanan - kompiler bebas untuk mengoptimalkan, hingga dan termasuk tidak pernah menyimpan nilai Anda di lokasi memori yang dapat diakses di luar garis tempat itu digunakan (register, instruksi encoding, dll).
rickster

62

Dalam kedua Objective-C dan Swift, yang ==dan !=uji operator untuk nilai kesetaraan bagi nilai-nilai nomor (misalnya, NSInteger, NSUInteger, int, di Objective-C dan Int, UInt, dll di Swift). Untuk objek (NSObject / NSNumber dan subclass di Objective-C dan tipe referensi di Swift), ==dan !=uji bahwa objek / tipe referensi adalah hal yang sama identik - yaitu, nilai hash yang sama - atau bukan hal yang sama identik, masing-masing .

let a = NSObject()
let b = NSObject()
let c = a
a == b // false
a == c // true

Operator kesetaraan identitas Swift , ===dan !==, periksa kesetaraan referensial - dan karenanya, mungkin harus disebut operator kesetaraan referensial IMO.

a === b // false
a === c // true

Penting juga untuk menunjukkan bahwa tipe referensi khusus di Swift (yang tidak mensubklasifikasikan kelas yang sesuai dengan Equatable) tidak secara otomatis mengimplementasikan yang sama dengan operator, tetapi identitas operator kesetaraan masih berlaku. Juga, dengan mengimplementasikan ==, !=secara otomatis diterapkan.

class MyClass: Equatable {
  let myProperty: String

  init(s: String) {
    myProperty = s
  }
}

func ==(lhs: MyClass, rhs: MyClass) -> Bool {
  return lhs.myProperty == rhs.myProperty
}

let myClass1 = MyClass(s: "Hello")
let myClass2 = MyClass(s: "Hello")
myClass1 == myClass2 // true
myClass1 != myClass2 // false
myClass1 === myClass2 // false
myClass1 !== myClass2 // true

Operator kesetaraan ini tidak diterapkan untuk tipe lain seperti struktur dalam bahasa apa pun. Namun, operator khusus dapat dibuat di Swift, yang akan, misalnya, memungkinkan Anda membuat operator untuk memeriksa kesetaraan CGPoint.

infix operator <==> { precedence 130 }
func <==> (lhs: CGPoint, rhs: CGPoint) -> Bool {
  return lhs.x == rhs.x && lhs.y == rhs.y
}

let point1 = CGPoint(x: 1.0, y: 1.0)
let point2 = CGPoint(x: 1.0, y: 1.0)
point1 <==> point2 // true

3
Maaf, tetapi dalam Obj-C operator == TIDAK membandingkan untuk EQUALITY, melainkan - seperti C - membandingkan referensi pointer (objek Identity).
Motti Shneor

==tidak menguji NSNumberkesetaraan dalam Objective-C. NSNumberadalah NSObjectjadi itu menguji identitas. Alasan mengapa SOMETIMES berfungsi adalah karena penunjuk yang ditandai / objek literal yang di-cache. Ini akan gagal untuk jumlah yang cukup besar dan pada perangkat 32-bit saat membandingkan non-literal.
Accatyyc

45

Dalam 3 cepat dan di atas

===(atau !==)

  • Memeriksa apakah nilainya identik (keduanya menunjuk ke alamat memori yang sama) .
  • Membandingkan tipe referensi .
  • Seperti ==di Obj-C (pointer equality).

==(atau !=)

  • Cek apakah nilainya sama .
  • Membandingkan tipe nilai .
  • Seperti default isEqual:dalam perilaku Obj-C.

Di sini saya membandingkan tiga contoh (kelas adalah tipe referensi)

class Person {}

let person = Person()
let person2 = person
let person3 = Person()

person === person2 // true
person === person3 // false

Anda juga dapat mengganti isEqual:di Swift:override func isEqual(_ object: Any?) -> Bool {}
Thomas Elliot

37

Ada seluk-beluk dengan Swift ===yang melampaui aritmatika pointer saja. Sementara di Objective-C Anda dapat membandingkan dua pointer (yaitu NSObject *) dengan== ini tidak lagi benar di Swift karena jenis memainkan peran yang jauh lebih besar selama kompilasi.

Taman Bermain akan memberi Anda

1 === 2                    // false
1 === 1                    // true
let one = 1                // 1
1 === one                  // compile error: Type 'Int' does not conform to protocol 'AnyObject'
1 === (one as AnyObject)   // true (surprisingly (to me at least))

Dengan string, kita harus terbiasa dengan ini:

var st = "123"                                 // "123"
var ns = (st as NSString)                      // "123"
st == ns                                       // true, content equality
st === ns                                      // compile error
ns === (st as NSString)                        // false, new struct
ns === (st as AnyObject)                       // false, new struct
(st as NSString) === (st as NSString)          // false, new structs, bridging is not "free" (as in "lunch")
NSString(string:st) === NSString(string:st)    // false, new structs
var st1 = NSString(string:st)                  // "123"
var st2 = st1                                  // "123"
st1 === st2                                    // true
var st3 = (st as NSString)                     // "123"
st1 === st3                                    // false
(st as AnyObject) === (st as AnyObject)        // false

tapi kemudian Anda juga bisa bersenang-senang sebagai berikut:

var st4 = st             // "123"
st4 == st                // true
st4 += "5"               // "1235"
st4 == st                // false, not quite a reference, copy on write semantics

Saya yakin Anda bisa memikirkan lebih banyak lagi kasus lucu :-)

Pembaruan untuk Swift 3 (seperti yang disarankan oleh komentar dari Jakub Truhlář)

1===2                                    // Compiler error: binary operator '===' cannot be applied to two 'Int' operands
(1 as AnyObject) === (2 as AnyObject)    // false
let two = 2
(2 as AnyObject) === (two as AnyObject)  // false (rather unpleasant)
(2 as AnyObject) === (2 as AnyObject)    // false (this makes it clear that there are new objects being generated)

Ini terlihat sedikit lebih konsisten dengan Type 'Int' does not conform to protocol 'AnyObject', namun kita dapatkan

type(of:(1 as AnyObject))                // _SwiftTypePreservingNSNumber.Type

tetapi konversi eksplisit membuat jelas bahwa mungkin ada sesuatu yang terjadi. Di sisi String hal-hal NSStringmasih akan tersedia selama kita import Cocoa. Maka kita akan punya

var st = "123"                                 // "123"
var ns = (st as NSString)                      // "123"
st == ns                                       // Compile error with Fixit: 'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?
st == ns as String                             // true, content equality
st === ns                                      // compile error: binary operator '===' cannot be applied to operands of type 'String' and 'NSString'
ns === (st as NSString)                        // false, new struct
ns === (st as AnyObject)                       // false, new struct
(st as NSString) === (st as NSString)          // false, new structs, bridging is not "free" (as in "lunch")
NSString(string:st) === NSString(string:st)    // false, new objects
var st1 = NSString(string:st)                  // "123"
var st2 = st1                                  // "123"
st1 === st2                                    // true
var st3 = (st as NSString)                     // "123"
st1 === st3                                    // false
(st as AnyObject) === (st as AnyObject)        // false

Masih membingungkan untuk memiliki dua kelas String, tetapi menjatuhkan konversi implisit mungkin akan membuatnya sedikit lebih gamblang.


2
Anda tidak dapat menggunakan ===operator untuk membandingkan Ints. Not in Swift 3.
Jakub Truhlář

Setiap kali Anda mengatakan "struct baru" sedang dibuat, apa yang sebenarnya terjadi adalah objek baru (dari tipe kelas ) sedang dibuat. ===tidak ada artinya untuk struct karena mereka tipe nilai. Secara khusus, ada tiga jenis yang perlu Anda ingat: tipe literal, seperti 1 atau "foo", yang belum terikat ke variabel dan biasanya hanya mempengaruhi kompilasi karena Anda biasanya tidak berurusan dengan mereka selama runtime; tipe struct seperti Intdan Stringmana yang Anda dapatkan ketika Anda menetapkan literal ke variabel, dan kelas-kelas seperti AnyObjectdan NSString.
saagarjha

12

Misalnya, jika Anda membuat dua instance kelas misalnya myClass:

var inst1 = myClass()
var inst2 = myClass()

Anda dapat membandingkan contoh-contoh itu,

if inst1 === inst2

dikutip:

yang Anda gunakan untuk menguji apakah dua referensi objek keduanya merujuk ke instance objek yang sama.

Kutipan dari: Apple Inc. “Bahasa Pemrograman Swift.” iBooks. https://itun.es/sk/jEUH0.l


11

Dalam Swift kita memiliki simbol === yang berarti kedua objek merujuk ke referensi yang sama dengan alamat yang sama

class SomeClass {
var a: Int;

init(_ a: Int) {
    self.a = a
}

}

var someClass1 = SomeClass(4)
var someClass2 = SomeClass(4)
someClass1 === someClass2 // false
someClass2 = someClass1
someClass1 === someClass2 // true

4

Hanya kontribusi kecil terkait Anyobjek.

Saya bekerja dengan unit test sekitar NotificationCenter, yang menggunakan Anyparameter yang ingin saya bandingkan untuk kesetaraan.

Namun, karena Anytidak dapat digunakan dalam operasi kesetaraan, perlu untuk mengubahnya. Pada akhirnya, saya memutuskan pada pendekatan berikut, yang memungkinkan saya untuk mendapatkan kesetaraan dalam situasi khusus saya, ditunjukkan di sini dengan contoh sederhana:

func compareTwoAny(a: Any, b: Any) -> Bool {
    return ObjectIdentifier(a as AnyObject) == ObjectIdentifier(b as AnyObject)
}

Fungsi ini memanfaatkan ObjectIdentifier , yang menyediakan alamat unik untuk objek, memungkinkan saya untuk menguji.

Satu item yang perlu diperhatikan ObjectIdentifierper Apple di tautan di atas:

Di Swift, hanya instance kelas dan metatypes yang memiliki identitas unik. Tidak ada gagasan identitas untuk struct, enum, fungsi, atau tupel.


2

==digunakan untuk memeriksa apakah dua variabel yaitu sama 2 == 2. Tetapi dalam kasus ===itu berdiri untuk kesetaraan yaitu jika dua contoh merujuk ke contoh objek yang sama dalam kasus kelas referensi dibuat yang dipegang oleh banyak contoh lainnya.


1

Swift 4: Contoh lain menggunakan Tes Unit yang hanya bekerja dengan ===

Catatan: Tes di bawah ini gagal dengan ==, berfungsi dengan ===

func test_inputTextFields_Delegate_is_ViewControllerUnderTest() {

        //instantiate viewControllerUnderTest from Main storyboard
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        viewControllerUnderTest = storyboard.instantiateViewController(withIdentifier: "StoryBoardIdentifier") as! ViewControllerUnderTest 
        let _ = viewControllerUnderTest.view

        XCTAssertTrue(viewControllerUnderTest.inputTextField.delegate === viewControllerUnderTest) 
    }

Dan kelasnya adalah

class ViewControllerUnderTest: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var inputTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        inputTextField.delegate = self
    }
}

Kesalahan dalam Tes Unit jika Anda menggunakan == adalah, Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.