web-dev-qa-db-fra.com

Swift Struct n'est pas conforme au protocole Equatable?

Comment rendre une structure conforme au protocole "Equatable"?

J'utilise Xcode 7.3.1

struct MyStruct {
   var id: Int
   var value: String

   init(id: Int, value: String) {
       self.id = id
       self.value = value
   }

   var description: String {
       return "blablabla"
   }

}

Lorsque j'utilise "MyStruct", Xcode affiche l'erreur:

MyStruct n'est pas conforme au protocole "Equatable"

Vous avez une idée pour rendre MyStruct conforme au protocole?

20
Insou

OK, après beaucoup de recherches, ça marche ...

struct MyStruct {
    var id: Int
    var value: String

    init(id: Int, value: String) {
        self.id = id
        self.value = value
    }

    var description: String {
        return "blablabla"
    }

}

extension MyStruct: Equatable {}

func ==(lhs: MyStruct, rhs: MyStruct) -> Bool {
    let areEqual = lhs.id == rhs.id &&
        lhs.value == rhs.value

    return areEqual
}

Mon Struct était dans une classe, donc ça n'a pas fonctionné .. J'ai retiré ce Struct de ma classe et maintenant c'est bon :)

18
Insou

Swift 4.1 (et supérieur) Réponse mise à jour:

À partir de Swift 4.1, tout ce que vous avez à faire est de vous conformer au protocole Equatable sans avoir à implémenter le == méthode. Voir: SE-0185 - Synthèse de conformité équitable et hashable .

Exemple:

struct MyStruct: Equatable {
    var id: Int
    var value: String
}

let obj1 = MyStruct(id: 101, value: "object")
let obj2 = MyStruct(id: 101, value: "object")

obj1 == obj2 // true


Gardez à l'esprit que le comportement par défaut du == est de comparer tout les propriétés du type (basé sur l'exemple: lhs.id == rhs.id && lhs.value == rhs.value). Si vous visez à obtenir un comportement personnalisé (en comparant une seule propriété par exemple), vous devez le faire vous-même:

struct MyStruct: Equatable {
    var id: Int
    var value: String
}

extension MyStruct {
    static func ==(lhs: MyStruct, rhs: MyStruct) -> Bool {
        return lhs.id == rhs.id
    }
}

let obj1 = MyStruct(id: 101, value: "obj1")
let obj2 = MyStruct(id: 101, value: "obj2")

obj1 == obj2 // true

À ce stade, l'égalité serait basée sur la valeur id, quelle que soit la valeur de value.

26
Ahmad F

Le problème n'est pas que la structure se trouve dans une classe. C'est certainement permis, et il y a de nombreux cas où vous voudrez peut-être le faire. Le problème réside dans la mise en œuvre du protocole Equatable. Vous devez donner une implémentation globale de == (ce que vous avez fait), mais il n'y a pas d'entité MyStruct .... c'est ParentClass.MyStruct (si la structure est définie dans une classe parent). L'exemple ci-dessous en soi n'est probablement pas un bon exemple dans ce cas, mais il montre comment vous pouvez le faire si nécessaire.

class ParentClass {

  struct MyStruct {
    var id: Int
    var value: String

    init(id: Int, value: String) {
      self.id = id
      self.value = value
    }

    var description: String {
      return "blablabla"
    }
  }
}

extension ParentClass.MyStruct: Equatable {}

func ==(lhs: ParentClass.MyStruct, rhs: ParentClass.MyStruct) -> Bool {
  let areEqual = lhs.id == rhs.id &&
    lhs.value == rhs.value

  return areEqual
}

let s1 = ParentClass.MyStruct(id: 1, value: "one")
let s2 = ParentClass.MyStruct(id: 2, value: "two")
let s3 = ParentClass.MyStruct(id: 1, value: "one")

s1.description    //blablabla

s1 == s2         //false
s3 == s1         //true

Remarque: j'aime implémenter Comparable plutôt qu'Equatable, ce qui vous permettra de prendre en charge le tri et d'autres fonctionnalités.

8
DJohnson