web-dev-qa-db-fra.com

Swift Protocol Implements Equatable

J'ai le Protocol ci-dessous:

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

Puis-je rendre Cacheable implements Equatable?

quand je fais ce qui suit:

extension Cacheable: Equatable {}

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

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

J'ai reçu ce message d'erreur: L'extension du protocole Cacheable ne peut pas avoir de clause d'héritage

34
Bobj-C

1) Autoriser la comparaison de deux Cacheable du même type

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

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

Avantages

C'est la solution la plus simple.

Les inconvénients

Vous ne pouvez comparer que deux objets Cacheable du même type. Cela signifie que le code ci-dessous échouera et pour le corriger, vous devez rendre Animal conforme à 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) Autoriser la comparaison de Cacheables de tout type

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

Avantages

Supprime les limitations décrites ci-dessus pour la solution 1. Vous pouvez désormais comparer facilement Dog et Cat.

Les inconvénients

  • La mise en œuvre est plus longue. En fait, je ne sais pas pourquoi spécifier uniquement == les fonctions ne sont pas suffisantes - cela pourrait être un bogue avec un compilateur. Quoi qu'il en soit, vous devez fournir l'implémentation à la fois == et !=.
  • Dans certains cas, l'avantage de cette implémentation peut également poser problème, car vous autorisez la comparaison entre des objets absolument différents et le compilateur est tout à fait d'accord avec cela.

3) Sans se conformer à 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()
}

Avantages

Vous pouvez utiliser Cacheable comme type sans avoir besoin de génériques. Cela introduit une toute nouvelle gamme de possibilités. Par exemple:

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

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

Avec les solutions 1 et 2, ce code échouerait et vous devriez utiliser des génériques dans vos classes. Cependant, avec la dernière implémentation, Cacheable est traité comme un type, vous êtes donc autorisé à déclarer un tableau de type [Cacheable].

Les inconvénients

Vous ne déclarez plus la conformité à Equatable donc toutes les fonctions qui acceptent les paramètres Equatable n'accepteront pas Cacheable. De toute évidence, à part == et != comme nous les avons déclarés pour Cacheables.

Si ce n'est pas un problème dans votre code, je préférerais en fait cette solution. Être capable de traiter le protocole comme un type est super utile dans de nombreux cas.

46
Andriy Gordiychuk

Essayer.

extension Equatable where Self : Cacheable {
}
11
njuri