在swift中似乎有两个相等运算符:double equals(==
)和triple equals(===
),两者之间有什么区别?
在这两种Objective-C和夫特中,==
和!=
运营商的测试用于数值的值相等(例如,NSInteger
,NSUInteger
,int
,在Objective-C和Int
,UInt
等在SWIFT).对于对象(Objective中的NSObject/NSNumber和子类以及Swift中的引用类型),==
并!=
测试对象/引用类型是相同的相同的东西 - 即相同的哈希值 - 或者不是相同的相同的东西,分别.
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
简而言之:
==
运算符检查它们的实例值是否相等, "equal to"
===
operator检查引用是否指向同一个实例, "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引用指向Heap区域中的两个不同实例,但它们的实例是相同的,因为它们的ssn数相等.所以输出将是the two instance are equal!
if person1 === person2 { //It does not enter here } else { print("the two instances are not identical!") }
===
operator检查引用是否指向同一个实例"identical to"
.由于person1和person2在Heap区域中有两个不同的实例,因此它们与输出不同the two instance are not identical!
let person3 = person1
P.S:
类是引用类型,person1的引用通过此赋值操作复制到person3,因此两个引用都指向堆区域中的相同实例.
if person3 === person1 { print("the two instances are identical!") }
它们是相同的,输出将是 the two instances are identical!
===
(或!==
)
检查值是否相同 (都指向相同的内存地址).
比较参考类型.
就像==
在Obj-C(指针相等)中一样.
==
(或!=
)
检查值是否相同.
比较值类型.
像isEqual:
Obj-C行为中的默认值一样.
这里我比较三个实例 (类是引用类型)
class Person {} let person = Person() let person2 = person let person3 = Person() person === person2 // true person === person3 // false
例如,如果您创建一个类的两个实例,例如myClass
:
var inst1 = myClass() var inst2 = myClass()
你可以比较这些实例,
if inst1 === inst2
引用:
用于测试两个对象引用是否都引用同一对象实例.
摘录自:Apple Inc."The Swift Programming Language."iBooks.https://itun.es/sk/jEUH0.l
!==
并且===
是身份运算符,用于确定两个对象是否具有相同的引用.
Swift还提供了两个标识运算符(===和!==),用于测试两个对象引用是否都引用同一个对象实例.
摘录自:Apple Inc."The Swift Programming Language."iBooks.https://itun.es/us/jEUH0.l
Swifts的微妙之处===
不仅仅是指针算术.在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类,但是在丢弃隐式转换可能会使其成为一个小更溢于言表.
在Swift中我们有=== simbol这意味着两个对象都指的是相同的引用相同的地址
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