==和===之间的区别


300

很快就有两个相等运算符:double equals(==)和Triple equals(===),两者之间有什么区别?

Answers:


149

简而言之:

== 操作员检查其实例值是否相等, "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!


248

!=====是身份运算符,用于确定两个对象是否具有相同的引用。

Swift还提供了两个标识运算符(===和!==),您可以使用它们来测试两个对象引用是否都引用同一对象实例。

摘录自:苹果公司“ The Swift Programming Language”。iBooks。https://itun.es/us/jEUH0.l


49
对。来自ObjC,==is isEqual:或类定义的语义对等。===Swift ==在(Obj)C中-指针相等或对象标识。
rickster 2014年

@rickster的值也没有存储位置吗?我最终他们在记忆中的某个地方。你不能比较那些吗?还是它们的存储位置没有提供任何有意义的价值?
亲爱的,2016年

2
至少有两种方法可以考虑该语言如何定义值类型与内存。一个是名称与值的每个绑定(varlet)都是唯一的副本-因此创建指针毫无意义,因为您创建的指针所指向的值与您初次创建的值不同。另一个是,Swift对值语义的定义将存储抽象化了-编译器可以自由地进行优化,甚至可以将值从未存储在超出其使用范围(寄存器,指令编码等)可访问的内存位置。
rickster '16

62

在这两种Objective-C和夫特中,==!=用于数值值相等运算测试(例如,NSIntegerNSUIntegerint,在Objective-C和IntUInt等在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

3
抱歉,但是在Obj-C中,==运算符不会比较EQUALITY,而是像C一样比较指针引用(对象标识)。
Motti Shneor

==不会NSNumber在Objective-C中测试是否相等。NSNumber是的NSObject,因此测试的身份。SOMETIMES之所以起作用,是因为标记了指针/缓存的对象文字。比较非文字时,它将在足够大的数字和32位设备上失败。
Accatyyc

45

快速3及以上

===(或!==

  • 检查值是否相同 (均指向相同的内存地址)
  • 比较参考类型
  • 就像==在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 {}
Thomas Elliot

37

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类,但是在丢弃隐式转换可能会使其成为一个更溢于言表。


2
您不能使用===运算符进行比较Ints。不是斯威夫特3
的JakubTruhlář

每当您说要创建“新结构”时,实际上是在创建一个新的(类型)对象。===对于结构而言,由于它们是值类型,因此毫无意义。特别是,您需要牢记三种类型:文字类型,例如1或“ foo”,它们没有绑定到变量,通常只影响编译,因为您通常在运行时不处理它们。结构类型(如Int和)String是将文字分配给变量时得到的结构类型,以及类(如AnyObject和)NSString
saagarjha

12

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

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

您可以比较这些实例,

if inst1 === inst2

引用:

用于测试两个对象引用是否都引用同一个对象实例。

摘录自:苹果公司“ The Swift Programming Language”。iBooks。https://itun.es/sk/jEUH0.l


11

在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

4

Any对象有关的贡献很小。

我当时正在使用进行单元测试NotificationCenterAny用作我想比较相等性的参数。

但是,由于Any不能在相等运算中使用,因此有必要进行更改。最终,我决定采用以下方法,该方法使我可以在自己的特定情况下获得平等,此处以一个简单的示例所示:

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

此功能利用了ObjectIdentifier,它为对象提供了唯一的地址,允许我进行测试。

ObjectIdentifier在以上链接中,每个苹果需要注意的一项:

在Swift中,只有类实例和元类型才具有唯一标识。对于结构,枚举,函数或元组,没有身份的概念。


2

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


1

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!'

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.