Hızlı bir şekilde iki eşitlik operatörü var gibi görünüyor: çift eşittir ( ==
) ve üçlü eşittir ( ===
), ikisi arasındaki fark nedir?
Hızlı bir şekilde iki eşitlik operatörü var gibi görünüyor: çift eşittir ( ==
) ve üçlü eşittir ( ===
), ikisi arasındaki fark nedir?
Yanıtlar:
Kısacası:
==
operatör örnek değerlerinin eşit olup olmadığını kontrol eder, "equal to"
===
operatör referansların aynı örneği gösterip göstermediğini kontrol eder, "identical to"
Uzun cevap:
Sınıflar referans türleridir, birden çok sabit ve değişkenin sahne arkasında bir sınıfın aynı tek örneğine başvurması mümkündür. Sınıf başvuruları Çalışma Süresi Yığını'nda (RTS) kalır ve örnekleri Bellek Yığın alanında kalır. Eşitliği kontrol ettiğinizde ==
, örneklerinin birbirine eşit olup olmadığı anlamına gelir. Eşit olmak için aynı örnek olması gerekmez. Bunun için özel sınıfınıza bir eşitlik kriteri sağlamanız gerekir. Varsayılan olarak, özel sınıflar ve yapılar, "eşittir" işleci ==
ve "eşit değil " işleci olarak bilinen denklik işleçlerinin varsayılan bir uygulamasını almaz !=
. Bunu yapmak için özel sınıfınızın Equatable
protokole uyması gerekir ve static func == (lhs:, rhs:) -> Bool
işlevi
Örneğe bakalım:
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.:
SSN (sosyal güvenlik numarası) benzersiz bir sayı olduğundan, adlarının eşit olup olmadığını karşılaştırmanız gerekmez.
let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")
if person1 == person2 {
print("the two instances are equal!")
}
Kişi1 ve kişi2 başvuruları Yığın alanında iki farklı örneği işaret etse de, örnekleri eşittir, çünkü ssn sayıları eşittir. Böylece çıktıthe two instance are equal!
if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}
===
operatör referansların aynı örneği gösterip göstermediğini kontrol eder "identical to"
. Kişi1 ve kişi2, Yığın alanında iki farklı örneğe sahip olduğundan, aynı değildir ve çıktıthe two instance are not identical!
let person3 = person1
P.S:
Sınıflar referans türleridir ve person1 referansı bu atama işlemiyle person3'e kopyalanır, böylece her iki referans da Yığın alanında aynı örneği gösterir.
if person3 === person1 {
print("the two instances are identical!")
}
Aynılar ve çıktılar the two instances are identical!
!==
ve ===
kimlik işleçleridir ve iki nesnenin aynı referansa sahip olup olmadığını belirlemek için kullanılır.
Swift ayrıca, iki nesne referansının her ikisinin de aynı nesne örneğine karşılık gelip gelmediğini test etmek için kullandığınız iki kimlik operatörü (=== ve! ==) sağlar.
Alıntı: Apple Inc. “Hızlı Programlama Dili”. iBooks. https://itun.es/us/jEUH0.l
var
veya let
) benzersiz bir kopyadır - bu nedenle işaretçi oluşturmak anlamsızdır çünkü işaretçi yaptığınız değer ilk oluşturduğunuz değerden farklı bir değerdir. Bir diğeri, Swift'in değer semantiği tanımının depolamayı soyutlamasıdır - derleyici, değerinizi kullanıldığı satırın ötesinde erişilebilir bir bellek konumuna (kayıt, talimat kodlaması, vb.) Kadar saklamak dahil olmak üzere optimize etmekte serbesttir.
Her iki amaç-C ve Swift olarak, ==
ve !=
sayı değerleri için değer eşitlik için kullanım testi (ör NSInteger
, NSUInteger
, int
, amaç-C ve Int
, UInt
vb Swift). Nesneler için (NSObject / NSNumber ve Objective-C'deki alt sınıflar ve Swift'teki referans türleri) ==
ve !=
nesnelerin / başvuru türlerinin aynı özdeş şey olduğunu, yani aynı karma değer olduğunu ya da aynı özdeş değer olmadığını test edin. .
let a = NSObject()
let b = NSObject()
let c = a
a == b // false
a == c // true
Swift'in kimlik eşitliği operatörleri ===
ve !==
referans eşitliğini kontrol edin - ve bu nedenle muhtemelen referans eşitlik operatörleri IMO olarak adlandırılmalıdır .
a === b // false
a === c // true
Ayrıca Swift'teki (Equatable'a uyan bir sınıfı alt sınıfa ayırmayan) özel referans türlerinin operatörlere eşit olarak otomatik olarak uygulanmadığını, ancak kimlik eşitliği operatörlerinin hala geçerli olduğunu belirtmek gerekir . Ayrıca, uygulayarak ==
, !=
otomatik olarak uygulanır.
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
Bu eşitlik operatörleri her iki dilde de yapılar gibi diğer türler için uygulanmaz. Bununla birlikte, Swift'te, örneğin bir CGPoint'in eşitliğini kontrol etmek için bir operatör oluşturmanıza olanak tanıyan özel işleçler oluşturulabilir.
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
==
NSNumber
Objective-C'de eşitliği test etmez . NSNumber
Bir olan NSObject
bu kimlik için test yüzden. SOMETIMES'in çalışmasının nedeni etiketli işaretçiler / önbelleğe alınmış nesne değişmezlerinden kaynaklanmaktadır. Değişmez değerleri karşılaştırırken yeterince büyük sayılar ve 32 bit aygıtlarda başarısız olur.
===
(veya !==
)==
Obj C (işaretçi eşitliği) 'de.==
(veya !=
)isEqual:
Obj-C davranışındaki varsayılan gibi .Burada üç örneği karşılaştırıyorum (sınıf bir referans türüdür)
class Person {}
let person = Person()
let person2 = person
let person3 = Person()
person === person2 // true
person === person3 // false
isEqual:
Swift'de de geçersiz kılabilirsiniz :override func isEqual(_ object: Any?) -> Bool {}
===
Sadece işaretçi aritmetiğinin ötesine geçen Swifts incelikleri vardır . Objective-C'de herhangi bir iki göstergeyi (yani NSObject *
) bununla karşılaştırabildiniz ==
, Swift'te artık doğru değil çünkü türler derleme sırasında çok daha fazla rol oynuyor.
Bir Oyun Alanı size
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))
Dizelerle buna alışmamız gerekecek:
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
ancak daha sonra aşağıdaki gibi eğlenebilirsiniz:
var st4 = st // "123"
st4 == st // true
st4 += "5" // "1235"
st4 == st // false, not quite a reference, copy on write semantics
Eminim çok daha komik durumlar düşünebilirsiniz :-)
Swift 3 güncellemesi (Jakub Truhlář tarafından yapılan yorumda belirtildiği gibi)
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)
Bu biraz daha tutarlı görünüyor Type 'Int' does not conform to protocol 'AnyObject'
, ancak daha sonra
type(of:(1 as AnyObject)) // _SwiftTypePreservingNSNumber.Type
ancak açık dönüşüm, bir şeyler olabileceğini açıkça gösterir. Dize tarafında, NSString
biz sürece biz hala kullanılabilir olacak import Cocoa
. Sonra sahip olacağız
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
İki String sınıfına sahip olmak hala kafa karıştırıcıdır, ancak örtük dönüşümü bırakmak muhtemelen biraz daha palpe edilebilir olacaktır.
===
Karşılaştırmak için operatörü kullanamazsınız Ints
. Swift 3'te değil
===
değer türleri olduğu için yapılar için anlamsızdır. Özellikle, aklınızda bulundurmanız gereken üç tür vardır: 1 veya "foo" gibi bir değişkene bağlı olmayan ve normalde yalnızca derlemeyi etkileyen, çalışma zamanı sırasında genellikle bunlarla uğraşmadığınız için değişmez türler; gibi yapı tipleri Int
ve String
siz ne zaman atama bir değişmez bir değişken ve sınıflara gibi olsun nelerdir AnyObject
ve NSString
.
Örneğin, bir sınıfın iki örneğini oluşturursanız örneğin myClass
:
var inst1 = myClass()
var inst2 = myClass()
bu örnekleri karşılaştırabilir,
if inst1 === inst2
anılan:
ki bu iki nesne başvurusunun her ikisinin de aynı nesne örneğine karşılık gelip gelmediğini test etmek için kullanılır.
Alıntı: Apple Inc. “Hızlı Programlama Dili”. iBooks. https://itun.es/sk/jEUH0.l
Swift'te === erkek var, bu da her iki nesnenin de aynı adrese aynı adrese başvurduğu anlamına geliyor
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
Any
Nesne ile ilgili küçük bir katkı .
Eşitlik için karşılaştırmak istediğim bir parametre olarak NotificationCenter
kullanılan birim testleri ile çalışıyordum Any
.
Ancak, Any
bir eşitlik operasyonunda kullanılamayacağı için, onu değiştirmek gerekiyordu. Nihayetinde, burada basit bir örnekle gösterilen özel durumumda eşitlik elde etmeme izin veren aşağıdaki yaklaşıma karar verdim:
func compareTwoAny(a: Any, b: Any) -> Bool {
return ObjectIdentifier(a as AnyObject) == ObjectIdentifier(b as AnyObject)
}
Bu işlev , nesne için benzersiz bir adres sağlayan ve test etmeme izin veren ObjectIdentifier öğesinden yararlanır .
ObjectIdentifier
Yukarıdaki bağlantıda Apple başına not edilmesi gereken bir öğe :
Swift'te yalnızca sınıf örnekleri ve metatipler benzersiz kimliklere sahiptir. Yapılar, sıralamalar, işlevler veya kaplumbağalar için kimlik kavramı yoktur.
==
iki değişkenin eşit olup olmadığını kontrol etmek için kullanılır yani
2 == 2
. Ancak ===
eşitlik durumunda, yani sınıflar durumunda aynı nesne örneğine atıfta bulunan iki örnek, diğer birçok örnek tarafından tutulan bir referans yaratılır.
Swift 4: Yalnızca === ile çalışan Birim Testleri kullanan başka bir örnek
Not: Aşağıdaki test == ile başarısız oluyor, === ile çalışıyor
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)
}
Ve sınıf varlık
class ViewControllerUnderTest: UIViewController, UITextFieldDelegate {
@IBOutlet weak var inputTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
inputTextField.delegate = self
}
}
== kullanırsanız Birim Testleri'ndeki hata, Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'
==
birisEqual:
ya da sınıf tanımlanmış semantik eşdeğerleri.===
Swift==
içinde (Obj) C - işaretçi eşitliği veya nesne kimliği.