Почему компилятор swift ведет себя иначе с оператором равенства с / без протокола Equatable

У меня есть очень простой класс на игровой площадке в Swift 4.0, который переопределяет оператор ==.

Я не понимаю, почему компилятор Swift не ведет себя так же, когда класс наследует / не наследует протокол Equatable.

Здесь класс при наследовании Equatable протокола

class Test: Equatable  {
    var value = 0

    init(_ initialValue:Int) {
        value = initialValue
    }

    static func == (lhs:Test, rhs:Test) -> Bool {
        return lhs.value == rhs.value ? true : false
    }
}

let test1 = Test(0)
var test4:Test? = nil

if test1 == test4 {
    print("test1 and test4 are equals")
} else {
    print("test1 not equals to test4")
}

Когда этот код выполняется, он отображает "test1 не равно test4". Это ожидаемое поведение.

Далее, когда я просто удаляю "Equatable" протокол из класса

class Test  {
    var value = 0

    init(_ initialValue:Int) {
        value = initialValue
    }

    static func == (lhs:Test, rhs:Test) -> Bool {
        return lhs.value == rhs.value ? true : false
    }
}

let test1 = Test(0)
let test3 = Test(0)

var test4:Test? = nil


if test1 == test4 {
    print("test1 and test4 are equals")
} else {
    print("test1 not equals to test4")
}

Я получаю ошибку компиляции на линии

if test1 == test4 {

со следующим сообщением: "Значение необязательного типа" Test? " не развернутый, вы хотели использовать "!" или "?"?

Почему поведение отличается с / без Equatable?

На самом деле, я также ожидал такую ​​же ошибку компиляции, когда класс наследовал от Equatable, потому что я сравнивал необязательный с необязательным.

Безопасно ли сравнивать необязательный с необязательным, когда класс наследует Equatable?

2 ответа

Решение

E сть == оператор

public func ==<T>(lhs: T?, rhs: T?) -> Bool where T : Equatable

который позволяет сравнивать два необязательных значения, если базовый тип Equatable , Этот оператор вызывается в вашем первом случае

let test1 = Test(0)
var test4:Test? = nil

if test1 == test4 { ... }

(и левый операнд автоматически оборачивается в необязательный.)

Если Test не соответствует Equatable тогда этот оператор не совпадает, так что нет == оператор принимает два Test? операнды. Поэтому ошибка компилятора.

Если вы нажмете на команду, соответствующую Equatable, вы попадете сюда:

/// ....
/// You can also use this OPERATOR TO COMPARE A NON-OPTIONAL VALUE TO AN
/// OPTIONAL that wraps the same type. The non-optional value is wrapped as an
/// optional before the comparison is made. In the following example, the
/// `numberToMatch` constant is wrapped as an optional before comparing to the
/// optional `numberFromString`:
///
///     let numberToFind: Int = 23
///     let numberFromString: Int? = Int("23")      // Optional(23)
///     if numberToFind == numberFromString {
///         print("It's a match!")
///     }
///     // Prints "It's a match!"
///
/// ....
public func ==<T>(lhs: T?, rhs: T?) -> Bool where T : Equatable

Но для версии, которая не соответствует Equatable, вы этого не получите. Он будет использовать только статическую функцию, которую вы предоставили.

Другие вопросы по тегам