Swift Struct doesn't conform to protocol Equatable?
Asked Answered
F

4

32

How do I make a structure conform to protocol "Equatable"?

I'm using 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"
   }

}

When I use "MyStruct", Xcode shows the error:

MyStruct does not conform to protocol "Equatable"

Do you have an idea to make MyStruct conform to protocol?

Flashover answered 31/5, 2016 at 9:12 Comment(0)
F
25

OK, after lots of searching, it's working...

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
}

My Struct was in a class, so it didn't work.. I moved this Struct out of my class and now it's good :)

Flashover answered 31/5, 2016 at 9:23 Comment(1)
See DJohnson's answer: being in a class wasn't the issueLiaoning
C
51

Swift 4.1 (and above) Updated answer:

Starting from Swift 4.1, all you have to is to conform to the Equatable protocol without the need of implementing the == method. See: SE-0185 - Synthesizing Equatable and Hashable conformance.

Example:

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


Keep in mind that the default behavior for the == is to compare all the type properties (based on the example: lhs.id == rhs.id && lhs.value == rhs.value). If you are aiming to achieve a custom behavior (comparing only one property for instance), you have to do it by yourself:

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

At this point, the equality would be based on the id value, regardless of what's the value of value.

Calomel answered 11/7, 2018 at 7:55 Comment(1)
This will be the right answer for most people who have this question going forward.Barramunda
F
25

OK, after lots of searching, it's working...

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
}

My Struct was in a class, so it didn't work.. I moved this Struct out of my class and now it's good :)

Flashover answered 31/5, 2016 at 9:23 Comment(1)
See DJohnson's answer: being in a class wasn't the issueLiaoning
W
8

The issue isn't that the struct is within a class. That is certainly allowable, and there are many instances where you might want to do that. The issue is in the implementation of the Equatable protocol. You have to give a global implementation of == (which you have done), but there is no entity MyStruct....it is ParentClass.MyStruct (if the struct is defined within a parent class). The example below in itself is probably not a good example in this case, but it does show how you can do this if needed.

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

Note: I like to implement Comparable rather than just Equatable, which will allow you to support sorting and other functionality.

Wear answered 31/5, 2016 at 13:17 Comment(1)
how to make as generic? so that I may use it in all of my class and structGeneralize
G
-4

Class and struct are different. Struct is value type, but class is reference type.

You cannot define struct in class. On the contrary, you cannot define class in struct.

Struct and class both can conform to any protocol including your custom protocol.

Gyro answered 31/5, 2016 at 9:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.