Answers:
简而言之:
==
操作员检查其实例值是否相等, "equal to"
===
操作员检查引用是否指向同一实例, "identical to"
长答案:
类是引用类型,可能有多个常量和变量在幕后引用类的同一单个实例。类引用保留在运行时堆栈(RTS)中,其实例保留在内存的堆区域中。当您控制平等时==
,意味着它们的实例是否彼此相等。它不必是相同的实例才能相等。为此,您需要为自定义类提供一个相等条件。默认情况下,自定义类和结构不接受等效运算符的默认实现,即“等于”运算符==
和“不等于”运算符!=
。为此,您的自定义类需要遵循Equatable
协议及其static func == (lhs:, rhs:) -> Bool
功能
让我们看一个例子:
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(社会保险号)是唯一的号码,因此您无需比较其名称是否相等。
let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")
if person1 == person2 {
print("the two instances are equal!")
}
尽管person1和person2引用在堆区域中指向两个不同的实例,但是它们的实例相等,因为它们的ssn编号相等。所以输出将是the two instance are equal!
if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}
===
操作员检查引用是否指向相同的实例"identical to"
。由于person1和person2在堆区域中有两个不同的实例,因此它们并不相同,并且输出the two instance are not identical!
let person3 = person1
P.S:
类是引用类型,并且通过此分配操作将person1的引用复制到person3,因此两个引用都在Heap区域中指向同一实例。
if person3 === person1 {
print("the two instances are identical!")
}
它们是相同的,输出将是 the two instances are identical!
!==
和===
是身份运算符,用于确定两个对象是否具有相同的引用。
Swift还提供了两个标识运算符(===和!==),您可以使用它们来测试两个对象引用是否都引用同一对象实例。
摘录自:苹果公司“ The Swift Programming Language”。iBooks。https://itun.es/us/jEUH0.l
var
或let
)都是唯一的副本-因此创建指针毫无意义,因为您创建的指针所指向的值与您初次创建的值不同。另一个是,Swift对值语义的定义将存储抽象化了-编译器可以自由地进行优化,甚至可以将值从未存储在超出其使用范围(寄存器,指令编码等)可访问的内存位置。
在这两种Objective-C和夫特中,==
和!=
用于数值值相等运算测试(例如,NSInteger
,NSUInteger
,int
,在Objective-C和Int
,UInt
等在SWIFT)。对于对象(NSObject的/ NSNumber的和亚类中Objective-C和在夫特引用类型),==
并且!=
测试该对象/引用类型是相同的相同的事情-即相同的散列值-或分别是不一样的相同的东西, 。
let a = NSObject()
let b = NSObject()
let c = a
a == b // false
a == c // true
Swift的身份相等运算符===
和和!==
检查参照相等-因此,应该将其称为参照相等运算符IMO。
a === b // false
a === c // true
还需要指出的是,Swift中的自定义引用类型(不子类化符合Equatable的类)不会自动实现等于操作符,但是身份相等操作符仍然适用。另外,通过实施==
,!=
会自动实施。
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
这些相等运算符未针对其他类型(例如,两种语言的结构)实现。但是,可以在Swift中创建自定义运算符,例如,它使您能够创建一个运算符来检查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
==
不会NSNumber
在Objective-C中测试是否相等。NSNumber
是的NSObject
,因此测试的身份。SOMETIMES之所以起作用,是因为标记了指针/缓存的对象文字。比较非文字时,它将在足够大的数字和32位设备上失败。
===
(或!==
)==
在Obj-C(指针相等)中一样。==
(或!=
)isEqual:
Obj-C行为中的默认行为。在这里,我比较了三个实例 (类是引用类型)
class Person {}
let person = Person()
let person2 = person
let person3 = Person()
person === person2 // true
person === person3 // false
isEqual:
在Swift中改写:override func isEqual(_ object: Any?) -> Bool {}
Swift的精妙之处===
不仅仅在于指针算法。在Objective-C中,您可以比较任意两个指针(即NSObject *
),==
在Swift中不再如此,因为类型在编译过程中起着更大的作用。
一个游乐场会给你
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))
使用字符串,我们将不得不习惯于此:
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
但随后您也可以享受以下乐趣:
var st4 = st // "123"
st4 == st // true
st4 += "5" // "1235"
st4 == st // false, not quite a reference, copy on write semantics
我相信您会想到更多有趣的情况:-)
Swift 3的更新(如JakubTruhlář的评论所建议)
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)
这看起来与更加一致Type 'Int' does not conform to protocol 'AnyObject'
,但是随后我们得到
type(of:(1 as AnyObject)) // _SwiftTypePreservingNSNumber.Type
但是显式转换清楚地表明可能正在发生某些情况。在字符串方面,NSString
只要我们保持可用import Cocoa
。然后我们将有
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
它仍然是混乱有两个String类,但是在丢弃隐式转换可能会使其成为一个小更溢于言表。
===
运算符进行比较Ints
。不是斯威夫特3
===
对于结构而言,由于它们是值类型,因此毫无意义。特别是,您需要牢记三种类型:文字类型,例如1或“ foo”,它们没有绑定到变量,通常只影响编译,因为您通常在运行时不处理它们。结构类型(如Int
和)String
是将文字分配给变量时得到的结构类型,以及类(如AnyObject
和)NSString
。
例如,如果您创建一个类的两个实例,例如myClass
:
var inst1 = myClass()
var inst2 = myClass()
您可以比较这些实例,
if inst1 === inst2
引用:
用于测试两个对象引用是否都引用同一个对象实例。
摘录自:苹果公司“ The Swift Programming Language”。iBooks。https://itun.es/sk/jEUH0.l
与Any
对象有关的贡献很小。
我当时正在使用进行单元测试NotificationCenter
,Any
用作我想比较相等性的参数。
但是,由于Any
不能在相等运算中使用,因此有必要进行更改。最终,我决定采用以下方法,该方法使我可以在自己的特定情况下获得平等,此处以一个简单的示例所示:
func compareTwoAny(a: Any, b: Any) -> Bool {
return ObjectIdentifier(a as AnyObject) == ObjectIdentifier(b as AnyObject)
}
此功能利用了ObjectIdentifier,它为对象提供了唯一的地址,允许我进行测试。
ObjectIdentifier
在以上链接中,每个苹果需要注意的一项:
在Swift中,只有类实例和元类型才具有唯一标识。对于结构,枚举,函数或元组,没有身份的概念。
==
用于检查两个变量是否相等,即
2 == 2
。但是在===
它代表相等的情况下,即如果在类的情况下两个实例引用同一对象实例,则创建一个引用,该引用由许多其他实例持有。
Swift 4:另一个使用单元测试的示例仅适用于===
注意:下面的测试失败,==,可以使用===
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)
}
而班级正在
class ViewControllerUnderTest: UIViewController, UITextFieldDelegate {
@IBOutlet weak var inputTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
inputTextField.delegate = self
}
}
如果使用==,则单元测试中的错误是, Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'
==
isisEqual:
或类定义的语义对等。===
Swift==
在(Obj)C中-指针相等或对象标识。