Swift Tips 013 - Using the === operator to compare objects by instance
每天了解一点不一样的 Swift 小知识
代码截图
小笔记
这段代码在说什么
在代码截图中,我们看到 Enemy 通过 InstanceEquatable
拓展遵循了 Equatable
协议并重载了 ==
运算符。声明了只有内存地址相等的状态下才符合 ==
的定义,此时 ==
与 ===
的含义相同。
在这个前提下,调用 contains
函数的含义就变成了判断 player 摧毁的 ememy 中,是否包含目标对象引用的内存地址,而不是与目标对象内容相同的实例。
=== 和 == 傻傻分不清楚
简单来说,Swift 中提供了两种用于判等的操作符,一个是 ==
,一个是 ===
==
通常是用于判定两个对象的内容是否相同
===
通常是用于判定两个对象引用的是否为同一块内存地址。
能说的更详细一点么
对于类类型会存在多个实例指向同一个内存地址的情况,这是由于类类型本身是引用类型的缘故,类引用保存在 RTS (Run Time Stack) 上,而它们的实例保存在内存的堆上。
当我们使用 ==
时,我们内心只是想验证两个实例是否相同,而不是验证两个实例是同一个实例。此时我们就需要提供一个验证两个实例相同的规则。
通常状态下,自定义类和结构体是没有默认的 ==
和 !=
行为,我们需要让这些类型遵守 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
}
}
由于 SSN(social security number)是一个独一无二的标识符,就类似我们的身份证号,我们在判定 2 个对象是否相同时,是不需要关心名字的,不是么?
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 instances are equal!
if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}
===` 操作符检查的是引用的内存地址是否相同。由于 person1 和 person2 是完全 2 个独立构造的实例,所以它们在堆上的地址,也就是内存地址是不一样的,所以输出的结果一定会是 `the two instances are not identical!
let person3 = person1
正如我们所说的那样,类类型是引用类型,上面这段代码将 person1 的引用赋值给了 person3,现在它们同时指向 person1 指向的内存地址。
if person3 === person1 {
print("the two instances are identical!")
}
这里我想不用我太多解释,你也应该能猜到输出的结果了吧,如果还是不清楚,别担心,我们继续解释一下,这时候由于 person1 和 person3 指向的内存地址一样,也就是符号了 ===
的定义,所以输出结果会是 the two instances are identical!
通过这些小例子,你弄清楚 ==
和 ===
了么?