== ve === arasındaki fark


300

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:


149

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 Equatableprotokole uyması gerekir ve static func == (lhs:, rhs:) -> Booliş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!


248

!==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


49
Evet. Objc gelen, ==bir isEqual: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.
rickster

@rickster Dont 'değerleri ayrıca bir hafıza konumuna sahip mi? Sonunda ben hafızada bir yerdeyim. Bunları hiç karşılaştıramaz mısın? Veya bellek konumlarının anlamlı bir değer sunmaması mı?
Bal

2
Dilin değer türlerini belleğe nasıl tanımladığını düşünmenin en az iki yolu vardır. Birincisi, bir adın bir değere olan her bağlaması ( varveya 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.
rickster

62

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, UIntvb 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

3
Maalesef, Obj-C'de == operatörü EQUALITY için karşılaştırma yapmaz, aksine C gibi - işaretçi referanslarını (nesne Kimliği) karşılaştırır.
Motti Shneor

==NSNumberObjective-C'de eşitliği test etmez . NSNumberBir olan NSObjectbu 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.
Accatyyc

45

Hızlı 3 ve üstü

===(veya !==)

  • Değerlerin aynı olup olmadığını kontrol eder (her ikisi de aynı bellek adresini gösterir) .
  • Referans türlerinin karşılaştırılması .
  • Gibi ==Obj C (işaretçi eşitliği) 'de.

==(veya !=)

  • Değerlerin aynı olup olmadığını kontrol eder .
  • Değer türlerinin karşılaştırılması .
  • 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 {}
Thomas Elliot

37

===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, NSStringbiz 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.


2
===Karşılaştırmak için operatörü kullanamazsınız Ints. Swift 3'te değil
Jakub Truhlář

Ne zaman "yeni bir yapı" yaratıldığını söylediğinizde, gerçekte olan yeni bir nesne ( sınıf türünden) yaratılıyor. ===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 Intve Stringsiz ne zaman atama bir değişmez bir değişken ve sınıflara gibi olsun nelerdir AnyObjectve NSString.
saagarjha

12

Ö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


11

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

4

AnyNesne ile ilgili küçük bir katkı .

Eşitlik için karşılaştırmak istediğim bir parametre olarak NotificationCenterkullanılan birim testleri ile çalışıyordum Any.

Ancak, Anybir 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 .

ObjectIdentifierYukarı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.


2

==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.


1

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!'

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.