2024-02-16 06:00:05

==和===的差值

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


当前回答

简而言之:

==运算符检查它们的实例值是否相等,"equal to"

===运算符检查引用是否指向同一个实例," same to"

长一点的回答:

Classes are reference types, it is possible for multiple constants and variables to refer to the same single instance of a class behind the scenes. Class references stay in Run Time Stack (RTS) and their instances stay in Heap area of Memory. When you control equality with == it means if their instances are equal to each other. It doesn't need to be same instance to be equal. For this you need to provide a equality criteria to your custom class. By default, custom classes and structures do not receive a default implementation of the equivalence operators, known as the “equal to” operator == and “not equal to” operator != . To do this your custom class needs to conform Equatable protocol and it's static func == (lhs:, rhs:) -> Bool function

让我们看一个例子:

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(社会安全号码)是一个唯一的号码,你不需要比较他们的名字是否相等。

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号码是相等的。因此输出将是两个实例相等!

if person1 === person2 {
   //It does not enter here
} else {
   print("the two instances are not identical!")
}

===运算符检查引用是否指向同一个实例," same to"。因为person1和person2在Heap区域中有两个不同的实例,所以它们不相同,两个实例的输出也不相同!

let person3 = person1

注:类是引用类型,person1的引用通过赋值操作被复制到person3,因此两个引用指向Heap区域中的同一个实例。

if person3 === person1 {
   print("the two instances are identical!")
}

它们是相同的,并且输出将是两个实例是相同的!

其他回答

简而言之:

==运算符检查它们的实例值是否相等,"equal to"

===运算符检查引用是否指向同一个实例," same to"

长一点的回答:

Classes are reference types, it is possible for multiple constants and variables to refer to the same single instance of a class behind the scenes. Class references stay in Run Time Stack (RTS) and their instances stay in Heap area of Memory. When you control equality with == it means if their instances are equal to each other. It doesn't need to be same instance to be equal. For this you need to provide a equality criteria to your custom class. By default, custom classes and structures do not receive a default implementation of the equivalence operators, known as the “equal to” operator == and “not equal to” operator != . To do this your custom class needs to conform Equatable protocol and it's static func == (lhs:, rhs:) -> Bool function

让我们看一个例子:

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(社会安全号码)是一个唯一的号码,你不需要比较他们的名字是否相等。

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号码是相等的。因此输出将是两个实例相等!

if person1 === person2 {
   //It does not enter here
} else {
   print("the two instances are not identical!")
}

===运算符检查引用是否指向同一个实例," same to"。因为person1和person2在Heap区域中有两个不同的实例,所以它们不相同,两个实例的输出也不相同!

let person3 = person1

注:类是引用类型,person1的引用通过赋值操作被复制到person3,因此两个引用指向Heap区域中的同一个实例。

if person3 === person1 {
   print("the two instances are identical!")
}

它们是相同的,并且输出将是两个实例是相同的!

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

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

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

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

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

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

关于每个Apple的ObjectIdentifier,有一点需要注意:

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

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)

这看起来更符合类型“Int”不符合协议“AnyObject”,但我们然后得到

type(of:(1 as AnyObject))                // _SwiftTypePreservingNSNumber.Type

但是显式转换清楚地表明可能会发生一些事情。 在字符串方面,NSString仍然是可用的,只要我们导入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 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
    }
}

在单元测试中,如果使用==,则二进制操作符“==”不能应用于类型为“UITextFieldDelegate?”和“ViewControllerUnderTest!”