==和===的差值

在swift中似乎有两个相等操作符:双等号(==)和三等号(===),两者之间有什么区别?

122568 次浏览

!=====是标识操作符,用于确定两个对象是否具有相同的引用。

Swift还提供了两个标识操作符(===和!==),用于测试两个对象引用是否都引用同一个对象实例。

摘自:苹果公司《快速编程语言》。“iBooks。https://itun.es/us/jEUH0.l

例如,如果你创建一个类的两个实例,例如myClass:

var inst1 = myClass()
var inst2 = myClass()

你可以比较这些例子,

if inst1 === inst2

引用:

,用于测试两个对象引用是否都引用

摘自:苹果公司《快速编程语言》。“iBooks。https://itun.es/sk/jEUH0.l

在Objective-C和Swift中,==!=操作符测试数值是否相等(例如,Objective-C中的NSIntegerNSUIntegerint和Swift中的IntUInt等)。对于对象(Objective-C中的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

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更新(由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)

这看起来与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 3及以上

===(或!==)

  • 检查值是否为相同的 (两者都指向相同的内存地址)
  • 比较引用类型
  • 比如Obj-C中的==(指针相等)。

==(或!=)

  • 检查值是否为相同的
  • 比较值类型
  • 比如Obj-C行为中的默认isEqual:

这里我比较三个例子 (类是引用类型)

class Person {}


let person = Person()
let person2 = person
let person3 = Person()


person === person2 // true
person === person3 // false

在Swift中,我们有= = =符号,这意味着两个对象都引用同一个引用同一个地址

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

只是一个与Any对象相关的小贡献。

我正在使用围绕NotificationCenter的单元测试,它使用Any作为参数,我想比较是否相等。

然而,由于Any不能用于相等操作,因此有必要对其进行更改。最终,我选择了以下方法,这让我在特定的情况下获得了平等,这里有一个简单的例子:

func compareTwoAny(a: Any, b: Any) -> Bool {
return ObjectIdentifier(a as AnyObject) == ObjectIdentifier(b as AnyObject)
}

这个函数利用了ObjectIdentifier,它为对象提供了唯一的地址,允许我进行测试。

在上面的链接中,关于每个Apple的ObjectIdentifier需要注意的一点是:

在Swift中,只有类实例和元类型具有唯一的标识。 对于结构体、枚举、函数或 元组。< / p >

简而言之:

==操作符检查它们的实例值是否相等

===操作符检查引用是否指向相同的实例"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!")
}

===操作符检查引用是否指向相同的实例"identical to"。由于person1和person2在Heap区域中有两个不同的实例,它们是不相同的,并且输出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 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!'

==用于检查两个变量是否相等 2 == 2。但在===的情况下,它代表相等,即如果两个实例引用相同的对象示例,在类的情况下,创建的引用由许多其他实例持有