Подтвердить что ты не робот

Swift Protocol реализует Equatable

У меня есть ниже Protocol:

protocol Cacheable {
    //....//
    func identifier() -> String
}

Могу ли я сделать Cacheable реализует Equableable?

когда я делаю следующее:

extension Cacheable: Equatable {}

func ==(lhs:Cacheable,rhs:Cacheable) -> Bool {

     return lhs.identifier() == rhs.identifier()
}

Я получил это сообщение об ошибке: Расширение протокола Cacheable не может иметь предложение наследования

4b9b3361

Ответ 1

1) Разрешить сравнивать Cacheable того же типа

protocol Cacheable: Equatable {
    //....//
    func identifier() -> String
}

func ==<T : Cacheable>(lhs: T, rhs: T) -> Bool {
    return lhs.identifier() == rhs.identifier()
}

Pros

Это простейшее решение.

Против

Вы можете сравнить только два объекта Cacheable того же типа. Это означает, что приведенный ниже код не сработает, и для его исправления вам нужно Animal соответствовать Cacheable:

class Animal {

}

class Dog: Animal,Cacheable {
    func identifier() -> String {
        return "object"
    }
}

class Cat: Animal,Cacheable {
    func identifier() -> String {
        return "object"
    }
}

let a = Dog()

let b = Cat()

a == b //such comparison is not allowed

2) Разрешить Cacheable любого типа для сравнения

protocol Cacheable:Equatable {
    //....//
    func identifier() -> String
}

func ==<T:Cacheable>(lhs: T, rhs: T) -> Bool {
    return lhs.identifier() == rhs.identifier()
}

func !=<T:Cacheable>(lhs: T, rhs: T) -> Bool {
    return lhs.identifier() != rhs.identifier()
}

func ==<T:Cacheable, U:Cacheable>(lhs: T, rhs: U) -> Bool {
    return lhs.identifier() == rhs.identifier()
}

func !=<T:Cacheable, U:Cacheable>(lhs: T, rhs: U) -> Bool {
    return lhs.identifier() != rhs.identifier()
}

Pros

Удаляет ограничения, описанные выше для решения 1. Теперь вы можете легко сравнить Dog и Cat.

Против

  • Реализация более длительная. На самом деле я не уверен, почему указание только функций == не является достаточным - это может быть ошибка с компилятором. Во всяком случае, вы должны обеспечить реализацию как для ==, так и !=.
  • В некоторых случаях преимущество этой реализации также может представлять проблему, поскольку вы позволяете сравнивать между абсолютно разными объектами и компилятором полностью в порядке с ней.

3) Без соответствия Equatable

protocol Cacheable {
    //....//
    func identifier() -> String
}

func ==(lhs: Cacheable, rhs: Cacheable) -> Bool {
    return lhs.identifier() == rhs.identifier()
}

func !=(lhs: Cacheable, rhs: Cacheable) -> Bool {
    return lhs.identifier() != rhs.identifier()
}

Pros

Вы можете использовать Cacheable как тип без каких-либо дженериков. Это открывает целый ряд возможностей. Например:

let c:[Cacheable] = [Dog(),RaceCar()]

c[0] == c[1]
c[0] != c[1]

С решениями 1 и 2 такой код потерпит неудачу, и вам придется использовать дженерики в ваших классах. Однако с последней версией Cacheable рассматривается как тип, поэтому вам разрешено объявлять массив типа [Cacheable].

Против

Вы больше не объявляете соответствие Equatable, поэтому любые функции, которые принимают параметры Equatable, не будут принимать Cacheable. Очевидно, кроме == и !=, как мы объявили их для Cacheable s.

Если это не проблема в коде, я бы предпочел это решение. Способность рассматривать протокол как тип во многих случаях очень полезна.

Ответ 2

Try.

extension Equatable where Self : Cacheable {
}