Di swift tampaknya ada dua operator kesetaraan: ganda sama dengan ( ==
) dan tiga sama dengan ( ===
), apa perbedaan antara keduanya?
Di swift tampaknya ada dua operator kesetaraan: ganda sama dengan ( ==
) dan tiga sama dengan ( ===
), apa perbedaan antara keduanya?
Jawaban:
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 Equatable
protokol dan static func == (lhs:, rhs:) -> Bool
fungsinya
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!
!==
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
var
atau 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).
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
==
tidak menguji NSNumber
kesetaraan dalam Objective-C. NSNumber
adalah NSObject
jadi 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.
===
(atau !==
)==
di Obj-C (pointer equality).==
(atau !=
)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
isEqual:
di Swift:override func isEqual(_ object: Any?) -> Bool {}
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 NSString
masih 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.
===
operator untuk membandingkan Ints
. Not in Swift 3.
===
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 Int
dan String
mana yang Anda dapatkan ketika Anda menetapkan literal ke variabel, dan kelas-kelas seperti AnyObject
dan NSString
.
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
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
Hanya kontribusi kecil terkait Any
objek.
Saya bekerja dengan unit test sekitar NotificationCenter
, yang menggunakan Any
parameter yang ingin saya bandingkan untuk kesetaraan.
Namun, karena Any
tidak 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 ObjectIdentifier
per 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.
==
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.
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!'
==
adalahisEqual:
, atau kesetaraan semantik yang ditentukan kelas.===
dalam Swift adalah==
dalam (Obj) C - pointer kesetaraan, atau identitas objek.