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ì?
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:
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ủ Equatable
giao thức và nó static func == (lhs:, rhs:) -> Bool
hoạ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!
!==
và ===
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
var
hoặ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.).
Trong cả hai Objective-C và Swift, ==
và !=
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) ==
và !=
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 , ===
và !==
, 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
==
không kiểm tra NSNumber
sự bằng nhau trong Objective-C. NSNumber
là một NSObject
vì 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.
===
(hoặc !==
)==
trong Obj-C (con trỏ bằng).==
(hoặc !=
)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
isEqual:
trong Swift:override func isEqual(_ object: Any?) -> Bool {}
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ứ NSString
vẫ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 .
===
toán tử để so sánh Ints
. Không có trong Swift 3.
===
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ư Int
và String
đó 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ư AnyObject
và NSString
.
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
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
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 Any
như một tham số mà tôi muốn so sánh cho sự bằng nhau.
Tuy nhiên, vì Any
khô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ề ObjectIdentifier
mỗ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.
==
đượ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.
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!'
==
là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.