Расширение протокола Swift, где Self: Equatable не работает - PullRequest
0 голосов
/ 22 октября 2018

Может кто-нибудь пролить свет на то, почему это не работает?Я получаю сообщение об ошибке Binary operator '==' cannot be applied to operands of type 'Self' and 'CustomEquatable'

protocol CustomEquatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool
}

extension CustomEquatable where Self: Equatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool {
        return self == other
    }
}

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

Давайте начнем с вашего CustomEquatable протокола, без расширения:

protocol CustomEquatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool
}

Давайте определим некоторые типы для использования в экспериментах:

struct A: Equatable {
    let name: String
}

struct B: Equatable {
    let id: Int
}

Предположим, мы хотим, чтобы A и B соответствовали CustomEquatable.Затем мы рассмотрим четыре случая:

  • Что означает a1.isEqualTo(a2) (где a1 и a2 имеют тип A)?
  • Что означает b1.isEqualTo(b2) означает (где b1 и b2 имеют тип B)?
  • Что означает a.isEqualTo(b) (где a - A, а b - B)?
  • Что означает b.isEqualTo(a) (где b - B, а a - A)?

Для первых двухварианты, возможные ответы: a1.isEqualTo(a2) тогда и только тогда, когда a1 == a2 и b1.isEqualTo(b2) тогда и только тогда, когда b1 == b2.

Для вторых двух случаев нам нужно решить, есть ли способ дляA равно B.Самое простое решение (я думаю) состоит в том, что A никогда не может равняться B.

Таким образом, мы можем записать соответствия следующим образом:

extension A: CustomEquatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool {
        return (other as? A) == self
    }
}

extension B: CustomEquatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool {
        return (other as? B) == self
    }
}

Единственная разница в этихдва соответствия - тип приведения (с правой стороны as?).Таким образом, мы можем выделить соответствия в расширение протокола следующим образом:

extension CustomEquatable where Self: Equatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool {
        return (other as? Self) == self
    }
}

С этим расширением протокола мы можем заставить A и B соответствовать CustomEquatable без реализации isEqualTo для каждого:

extension A: CustomEquatable { }
extension B: CustomEquatable { }

Для проверки кода:

let a1 = A(name: "a1")
let a2 = A(name: "a2")
let b1 = B(id: 1)
let b2 = B(id: 2)

a1.isEqualTo(a1) // true
a1.isEqualTo(a2) // false
b1.isEqualTo(b1) // true
b1.isEqualTo(b2) // false
a1.isEqualTo(b1) // false
b1.isEqualTo(a1) // false
0 голосов
/ 22 октября 2018

Пожалуйста, смотрите WWDC 2015 Протоколно-ориентированное программирование в Swift из 37: 25

Это почти буквально взято из видео.Вы должны условно понизить значение other до Self.
Если это один и тот же тип, вы можете использовать ==, иначе оба объекта в любом случае не равны.

protocol CustomEquatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool
}
extension CustomEquatable where Self: Equatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool {
        if let other = other as? Self { return self == other }
        return false
    }
}
...