Sự khác biệt giữa == và ===


299

Trong swift dường như có hai toán tử đẳng thức: double bằng ( ==) và triple bằng ( ===), sự khác biệt giữa hai là gì?

Câu trả lời:


149

Nói ngắn gọn:

== toán tử kiểm tra nếu giá trị cá thể của chúng bằng nhau, "equal to"

=== toán tử kiểm tra nếu các tham chiếu trỏ cùng một thể hiện, "identical to"

Câu trả lời dài:

Các lớp là các kiểu tham chiếu, có thể nhiều hằng số và biến tham chiếu đến cùng một thể hiện của một lớp đằng sau hậu trường. Các tham chiếu lớp nằm trong Run Time Stack (RTS) và các thể hiện của chúng nằm trong vùng Heap của Bộ nhớ. Khi bạn kiểm soát sự bình đẳng với ==nó có nghĩa là nếu các thể hiện của chúng bằng nhau. Nó không cần phải giống nhau để được bằng nhau. Đối với điều này, bạn cần cung cấp một tiêu chí bình đẳng cho lớp tùy chỉnh của bạn. Theo mặc định, các lớp và cấu trúc tùy chỉnh không nhận được một triển khai mặc định của các toán tử tương đương, được gọi là Toán tử bằng với toán tử ==và và không bằng toán tử !=. Để làm điều này, lớp tùy chỉnh của bạn cần tuân thủ Equatablegiao thức và nó static func == (lhs:, rhs:) -> Boolhoạt động

Hãy xem ví dụ:

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.: Vì ssn (số an sinh xã hội) là một số duy nhất, bạn không cần so sánh xem tên của chúng có bằng nhau hay không.

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

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

Mặc dù tham chiếu person1 và person2 chỉ ra hai trường hợp khác nhau trong khu vực Heap, nhưng các thể hiện của chúng bằng nhau vì số ssn của chúng bằng nhau. Vì vậy, đầu ra sẽ làthe two instance are equal!

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

===toán tử kiểm tra nếu các tham chiếu trỏ cùng một thể hiện , "identical to". Vì person1 và person2 có hai thể hiện khác nhau trong vùng Heap, chúng không giống nhau và đầu rathe two instance are not identical!

let person3 = person1

P.S: Các lớp là các kiểu tham chiếu và tham chiếu của person1 được sao chép sang person3 với thao tác gán này, do đó cả hai tham chiếu đều trỏ cùng một thể hiện trong vùng Heap.

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

Chúng giống hệt nhau và đầu ra sẽ là the two instances are identical!


248

!=====là các toán tử nhận dạng và được sử dụng để xác định xem hai đối tượng có cùng tham chiếu hay không.

Swift cũng cung cấp hai toán tử nhận dạng (=== và! ==), mà bạn sử dụng để kiểm tra xem hai tham chiếu đối tượng có tham chiếu đến cùng một đối tượng không.

Trích từ: Apple Inc., Ngôn ngữ lập trình Swift. Sách điện tử. https://itun.es/us/jEUH0.l


49
Vâng Đến từ ObjC, ==isEqual:, hay đẳng cấp được xác định tương đương ngữ nghĩa. ===trong Swift là ==trong (Obj) C - đẳng thức con trỏ hoặc nhận dạng đối tượng.
gà trống

@rickster Giá trị của Dont 'cũng có vị trí bộ nhớ? Cuối cùng tôi cũng ở đâu đó trong ký ức. Bạn có thể so sánh chúng không? Hoặc là vị trí bộ nhớ của họ không cung cấp bất kỳ giá trị có ý nghĩa ?
Mật ong

2
Có ít nhất hai cách để suy nghĩ về cách ngôn ngữ xác định loại giá trị so với bộ nhớ. Một là mỗi ràng buộc ( varhoặc let) của một tên với một giá trị là một bản sao duy nhất - vì vậy việc tạo con trỏ là vô nghĩa vì giá trị bạn tạo con trỏ là một giá trị khác với giá trị bạn tạo lần đầu. Một điều nữa là định nghĩa về ngữ nghĩa giá trị của Swift trừu tượng hóa việc lưu trữ - trình biên dịch có thể tự do tối ưu hóa, tối đa và bao gồm không bao giờ lưu trữ giá trị của bạn tại một vị trí bộ nhớ có thể truy cập ngoài dòng được sử dụng (đăng ký, mã hóa lệnh, v.v.).
gà trống

62

Trong cả hai Objective-C và Swift, ==!=kiểm tra các nhà khai thác cho giá trị bình đẳng cho các giá trị số (ví dụ NSInteger, NSUInteger, int, trong Objective-C và Int, UInt, vv trong Swift). Đối với các đối tượng (NSObject / NSNumber và các lớp con trong Objective-C và các loại tham chiếu trong Swift) ==!=kiểm tra xem các đối tượng / loại tham chiếu có cùng một thứ - nghĩa là, cùng một giá trị băm - hoặc không giống nhau .

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

Các toán tử bình đẳng danh tính của Swift , ===!==, kiểm tra đẳng thức tham chiếu - và do đó, có lẽ nên được gọi là toán tử đẳng thức tham chiếu IMO.

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

Cũng đáng chỉ ra rằng các loại tham chiếu tùy chỉnh trong Swift (không phân lớp một lớp phù hợp với Equitable) không tự động thực hiện bằng với các toán tử, nhưng các toán tử đẳng thức nhận dạng vẫn được áp dụng. Ngoài ra, bằng cách thực hiện ==, !=được tự động thực hiện.

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

Các toán tử đẳng thức này không được triển khai cho các loại khác như cấu trúc trong một trong hai ngôn ngữ. Tuy nhiên, các toán tử tùy chỉnh có thể được tạo trong Swift, ví dụ, điều này sẽ cho phép bạn tạo một toán tử để kiểm tra sự bằng nhau của 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
Xin lỗi, nhưng trong Obj-C, toán tử == KHÔNG so sánh với THIẾT BỊ, mà là - giống như C - so sánh các tham chiếu con trỏ (Nhận dạng đối tượng).
Motti Shneor

==không kiểm tra NSNumbersự bằng nhau trong Objective-C. NSNumberlà một NSObjectvì vậy nó kiểm tra danh tính. Lý do nó SOMETIMES hoạt động là vì các con trỏ được gắn thẻ / các ký tự đối tượng được lưu trữ. Nó sẽ thất bại đối với số lượng đủ lớn và trên các thiết bị 32 bit khi so sánh không theo nghĩa đen.
Accatyyc

45

Trong swift 3 trở lên

===(hoặc !==)

  • Kiểm tra xem các giá trị có giống nhau không (cả hai đều trỏ đến cùng một địa chỉ bộ nhớ) .
  • So sánh các loại tài liệu tham khảo .
  • Giống như ==trong Obj-C (con trỏ bằng).

==(hoặc !=)

  • Kiểm tra nếu các giá trị là như nhau .
  • So sánh các loại giá trị .
  • Giống như mặc định isEqual:trong hành vi Obj-C.

Ở đây tôi so sánh ba trường hợp (lớp là một kiểu tham chiếu)

class Person {}

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

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

Bạn cũng có thể ghi đè isEqual:trong Swift:override func isEqual(_ object: Any?) -> Bool {}
Thomas Elliot

37

Có sự tinh tế với Swifts ===vượt xa các chỉ số con trỏ. Mặc dù trong Objective-C, bạn có thể so sánh bất kỳ hai con trỏ (nghĩa là NSObject *) với ==điều này không còn đúng trong Swift vì các kiểu đóng vai trò lớn hơn nhiều trong quá trình biên dịch.

Một sân chơi sẽ cung cấp cho bạn

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))

Với các chuỗi chúng ta sẽ phải làm quen với điều này:

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

nhưng sau đó bạn cũng có thể vui chơi như sau:

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

Tôi chắc chắn bạn có thể nghĩ ra nhiều trường hợp hài hước hơn :-)

Cập nhật cho Swift 3 (như được đề xuất bởi nhận xét từ 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)

Điều này có vẻ phù hợp hơn một chút Type 'Int' does not conform to protocol 'AnyObject', tuy nhiên sau đó chúng tôi nhận được

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

nhưng chuyển đổi rõ ràng làm rõ rằng có thể có một cái gì đó đang xảy ra. Về phía Chuỗi mọi thứ NSStringvẫn sẽ có sẵn miễn là chúng tôi import Cocoa. Rồi chúng ta sẽ có

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

Vẫn còn khó hiểu khi có hai lớp String, nhưng việc bỏ chuyển đổi ngầm có thể sẽ khiến nó trở nên rõ ràng hơn một chút .


2
Bạn không thể sử dụng ===toán tử để so sánh Ints. Không có trong Swift 3.
Jakub Truhlář

Bất cứ khi nào bạn nói một "cấu trúc mới" đang được tạo, những gì thực sự xảy ra là một đối tượng mới (thuộc loại lớp ) sẽ được tạo. ===là vô nghĩa đối với các cấu trúc vì chúng là loại giá trị. Cụ thể, có ba loại bạn cần ghi nhớ: loại chữ, chẳng hạn như 1 hoặc "foo", không bị ràng buộc với một biến và thường chỉ ảnh hưởng đến việc biên dịch vì bạn thường không xử lý chúng trong thời gian chạy; các kiểu cấu trúc như IntStringđó là những gì bạn nhận được khi bạn gán một chữ cho một biến và các lớp như AnyObjectNSString.
saagarjha

12

Ví dụ: nếu bạn tạo hai phiên bản của một lớp, ví dụ myClass:

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

bạn có thể so sánh những trường hợp đó,

if inst1 === inst2

trích dẫn:

mà bạn sử dụng để kiểm tra xem hai tham chiếu đối tượng đều tham chiếu đến cùng một đối tượng.

Trích từ: Apple Inc., Ngôn ngữ lập trình Swift. Sách điện tử. https://itun.es/sk/jEUH0.l


11

Trong Swift, chúng ta có === simbol, có nghĩa là cả hai đối tượng đều tham chiếu đến cùng một địa chỉ

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

Chỉ là một đóng góp nhỏ liên quan đến Anyđối tượng.

Tôi đã làm việc với các bài kiểm tra đơn vị xung quanh NotificationCenter, sử dụng Anynhư một tham số mà tôi muốn so sánh cho sự bằng nhau.

Tuy nhiên, vì Anykhông thể được sử dụng trong một hoạt động bình đẳng, nên cần phải thay đổi nó. Cuối cùng, tôi đã giải quyết theo cách tiếp cận sau, cho phép tôi có được sự bình đẳng trong tình huống cụ thể của mình, được hiển thị ở đây với một ví dụ đơn giản:

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

Hàm này tận dụng ObjectIdentifier , cung cấp một địa chỉ duy nhất cho đối tượng, cho phép tôi kiểm tra.

Một mục cần lưu ý về ObjectIdentifiermỗi Apple tại liên kết trên:

Trong Swift, chỉ các thể hiện lớp và siêu dữ liệu có danh tính duy nhất. Không có khái niệm về danh tính cho các cấu trúc, enum, hàm hoặc bộ dữ liệu.


2

==được sử dụng để kiểm tra nếu hai biến bằng nhau tức là 2 == 2. Nhưng trong trường hợp ===nó là viết tắt của đẳng thức, nghĩa là nếu hai trường hợp tham chiếu đến cùng một ví dụ đối tượng trong trường hợp các lớp thì một tham chiếu được tạo ra được giữ bởi nhiều trường hợp khác.


1

Swift 4: Một ví dụ khác sử dụng Bài kiểm tra đơn vị chỉ hoạt động với ===

Lưu ý: Kiểm tra bên dưới không thành công với ==, hoạt động với ===

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) 
    }

Và lớp học

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

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

Lỗi trong Kiểm tra đơn vị nếu bạn sử dụng == là, Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.