为什么我必须添加!=才能使比较正确?
import UIKit
class Person: NSObject {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
extension Person {
static func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.name == rhs.name && lhs.age == rhs.age
}
static func !=(lhs: Person, rhs: Person) -> Bool {
return !(lhs == rhs)
}
}
let first = Person(name: "John", age: 26)
let second = Person(name: "John", age: 26)
/**
* return false (which is correct) when we implement != function. But,
* it will return true if we don't implement the != function.
*/
first != second
更新
所以我知道为什么我必须添加!=
函数才能使它工作。这是因为该类继承了在场景后使用NSObject
方法的isEqual
。但是为什么添加!=
函数会使它工作?这里有任何解释吗?
答案 0 :(得分:3)
NSObject
符合Equatable
但使用自己的isEqual
方法,就isEqual
而言,两个实例都不相等。仅当NSObject
的表单已实施且包含==
时,!=
才会调用==
。
如果您删除NSObject
(并添加Equatable
),则==
的实施工作正常。
NSObject
的推荐方法是使用自定义实现覆盖isEqual
并省略==
(以及!=
)。
答案 1 :(得分:2)
很抱歉,这不是您问题的直接答案。
正如Alexander评论的那样,Swift标准库具有!=
的默认实现:
@_transparent
public static func != (lhs: Self, rhs: Self) -> Bool {
return !(lhs == rhs)
}
我无法很好地解释这种行为,但上面默认实现中的==
运算符已解决为==
的默认NSObject
运算符,NSObject
(以及它的后代已经Equatable
并且有==
运算符符合Equatable
。因此,即使显式表示与您的!=
定义完全相同,==
运算符也会针对不同的实现进行求解。
用于定义自己与NSObject
- 后代类的相等性的通用指南:
使==
和isEqual(_:)
保持一致
您可以将班级的实例存储在NSArray
或NSDictionary
内(在很多情况下会隐式)。在他们的方法中,当需要进行相等性检查时使用isEqual(_:)
,而不是==
运算符。
因此,只需定义==
运算符而不向isEqual(_:)
提供一致的覆盖,此类方法将产生意外结果。
要保持一致==
和isEqual(_:)
,
只覆盖isEqual(_:)
,不要明确定义==
和!=
。
==
(以及NSObject
)!=
的默认实施使用isEqual(_:)
。
class Person: NSObject {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
override func isEqual(_ object: Any?) -> Bool {
if let other = object as? Person {
return self.name == other.name && self.age == other.age
}
return false
}
}
(请参阅底部的 ONE MORE THING 。)
<强> ADDITION 强>
可以在非NSObject
类上找到类似的行为。
class BaseClass {
var a: Int
init(a: Int) {
self.a = a
}
}
extension BaseClass: Equatable {
static func == (lhs: BaseClass, rhs: BaseClass) -> Bool {
print("`==` of BaseClass")
return lhs.a == rhs.a
}
}
let b1 = BaseClass(a: 0)
let b2 = BaseClass(a: 0)
print(b1 != b2) //->`==` of BaseClass, false ### as expected
class DerivedClass: BaseClass {
var b: Int
init(a: Int, b: Int) {
self.b = b
super.init(a: a)
}
}
extension DerivedClass {
static func == (lhs: DerivedClass, rhs: DerivedClass) -> Bool {
print("`==` of DerivedClass")
return lhs.a == rhs.a && lhs.b == rhs.b
}
}
let d1 = DerivedClass(a: 0, b: 1)
let d2 = DerivedClass(a: 0, b: 2)
print(d1 != d2) //->`==` of BaseClass, false ### `==` of DerivedClass and true expected
对于已经==
类重写Equatable
,我们需要格外小心。
还有一件事
(感谢Hamish。)
您知道在创建符合==
的类型时,您需要始终如一地实施hashValue
和Hashable
。 NSObject
被声明为Hashable
,其hashValue
需要与hash
一致。因此,当您覆盖isEqual(_:)
- 后代中的NSObject
时,您还应覆盖与被覆盖的hash
一致的isEqual(_:)
。
所以,你的Person
类应该是这样的:
class Person: NSObject {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
override func isEqual(_ object: Any?) -> Bool {
if let other = object as? Person {
return self.name == other.name && self.age == other.age
}
return false
}
override var hash: Int {
//### This is just an example, but not too bad in practical use cases.
return name.hashValue ^ age.hashValue
}
}
答案 2 :(得分:1)
你在做什么是错的。您不应该实施==
或!=
。 NSObject子类自动将==
实现为isEqual:
。你正在扰乱这一点。你应该实现isEqual:
,这就是全部。