Разница между == и ===



в swift, кажется, есть два оператора равенства: double equals (==) и тройка равна (===), в чем разница между ними?

667   10  

10 ответов:

короче:

== оператор проверяет, равны ли их значения экземпляра,"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 с этой операцией присваивания, таким образом, обе ссылки указывают на один и тот же экземпляр в области кучи.

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

они идентичны и выход будет the two instances are identical!

!== и === являются операторами идентификации и используются для определения того, имеют ли два объекта одну и ту же ссылку.

Swift также предоставляет два оператора идентификации (=== и != = ), который используется для проверки того, ссылаются ли две ссылки на объект на один и тот же экземпляр объекта.

Отрывок Из: Apple Inc. "Язык Программирования Swift."iBooks. https://itun.es/us/jEUH0.l

как в Objective-C, так и в Swift, the == и != операторы проверяют равенство значений для числовых значений (например,NSInteger,NSUInteger,int, в Objective-C и Int,UInt и т. д. в Swift). Для объектов (NSObject/NSNumber и подклассы в Objective-C и ссылочные типы в Swift),== и != проверьте, что объекты / ссылочные типы являются одной и той же идентичной вещью-т. е. одним и тем же хэш-значением-или не являются одинаковыми, соответственно.

let a = NSObject()
let b = NSObject()
let c = a
a == b // false
a == c // true

Свифт тож равенства операторы === и !==, проверьте ссылочное равенство, и, таким образом, вероятно, следует называть равенство ссылок операторы ИМО.

a === b // false
a === c // true

также стоит отметить, что пользовательские ссылочные типы в Swift (которые не подклассируют класс, соответствующий Equatable) автоматически не реализуют операторы equal to, но тож равенства операторы все еще применяются. Кроме того, путем реализации ==,!= автоматически реализован.

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

есть тонкости со Стриж === это выходит за рамки простой арифметики указателя. В то время как в Objective-C вы смогли сравнить любые два указателя (т. е. NSObject *) С == это уже не так быстро так как типы играют гораздо большую роль во время компиляции.

детская площадка даст вам

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 (как предлагается в комментарии от Якуб 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

по-прежнему запутанно иметь два строковых класса, но удаление неявного преобразования, вероятно, сделает его мало более ощутима.

в swift 3 и выше

=== (или !==)

  • проверяет, если значения одинаковых(оба указывают на один и тот же адрес памяти).
  • сравнение ссылка типа.
  • как == В 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. "Язык Программирования Swift."iBooks. https://itun.es/sk/jEUH0.l

в 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

просто незначительный вклад, связанный с С Any не может использоваться в операции равенства, необходимо было изменить его. В конечном счете, я остановился на следующем подходе, который позволил мне получить равенство в моей конкретной ситуации, показанной здесь с упрощенным пример:

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

эта функция использует ObjectIdentifier, который предоставляет уникальный адрес для объекта, что позволяет мне проверить.

один пункт, чтобы отметить, хотя о ObjectIdentifier за Яблоко по ссылке выше:

в Swift только экземпляры классов и метатипы имеют уникальные идентификаторы. Нет понятия идентичности для структур, перечислений, функций или кортежи.

== используется для проверки равенства двух переменных, т. е. 2 == 2. Но в случае === это означает равенство, т. е. если два экземпляра ссылаются на один и тот же пример объекта в случае классов создается ссылка, которая хранится во многих других экземплярах.

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
    }
}

ошибка в модульных тестах, если вы используете == is,Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'

Comments

    Ничего не найдено.