Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do an if-else comparison on enums with arguments [duplicate]

Tags:

enums

swift

Language: Swift2.3

For example let's I'll show you different kinds of enums

enum Normal {     case one     case two, three }  enum NormalRaw: Int {     case one     case two, three }  enum NormalArg {     case one(Int)     case two, three }    

Switch can be used on all three enums like so:

var normal: Normal = .one var normalRaw: NormalRaw = .one var normalArg: NormalArg = .one(1)  switch normal {     case .one: print("1")     default: break }  switch normalRaw {     case .one: print(normalRaw.rawValue)     default: break }  switch normalArg {     case .one(let value): print(value)     default: break } 

On the if-else statement though I can only do comparison for Normal and NormalRaw, and an error message shows for NormalArg, so I can't run the code

Binary Operator '==' cannot be applied to operands of type NormalArg and _

Here's the code example:

if normal == .two { // no issue     .. do something }  if normalRaw == .two { // no issue     .. do something }  if normalArg == .two { // error here (the above message)     .. do something }  if normalArg == .one(_) { // error here (the above message)     .. do something }  if normalArg == .three { // error here (the above message)     .. do something } 

Any Ideas? I'm not really doing anything with this code, I'm just wondering as to why we can't do comparison.

like image 499
Zonily Jame Avatar asked May 19 '17 03:05

Zonily Jame


People also ask

How do you compare enums with strings?

For comparing String to Enum type you should convert enum to string and then compare them. For that you can use toString() method or name() method. toString()- Returns the name of this enum constant, as contained in the declaration.

Do enums have strong or weak references in memory?

We can tell that enum holds a strong reference to its associated values based on the fact that Swift Optional implements using enum, and it can hold any object reference without releasing it.

Can you compare enums in C++?

Enum Class Class enum doesn't allow implicit conversion to int, and also doesn't compare enumerators from different enumerations.


2 Answers

The trick is to not actually check with == but rather use the case keyword in conjunction with a single = in your if statement. This is a little counter intuitive in the beginning but just like if let, you get used to it pretty fast:

enum Normal {     case one     case two, three }  enum NormalRaw: Int {     case one = 1     case two, three }  enum NormalArg {     case one(Int)     case two, three }   let normalOne = Normal.one let normalRawOne = NormalRaw.one let normalArgOne = NormalArg.one(1)  if case .one = normalOne {     print("A normal one") //prints "A normal one" }  if case .one = normalRawOne {     print("A normal \(normalRawOne.rawValue)") //prints "A normal 1" }  if case .one(let value) = normalArgOne {     print("A normal \(value)") //prints "A normal 1" } 

The point is that in Swift you only get equation of enums for free if your enum uses a raw type or if you have no associated values (try it out, you can't have both at the same time). Swift however does not know how to compare cases with associated values - I mean how could it? Let's look at this example:

Normal.one == .one //true Normal.one == .two //false  NormalRaw.one == .one //true NormalRaw.one == .two //false  NormalArg.one(1) == .one(1) //Well...? NormalArg.one(2) == .one(1) //Well...? NormalArg.one(1) == .two //Well...? 

Maybe this makes it clearer why this cannot work out of the box:

class Special {     var name: String?     var special: Special? }  enum SpecialEnum {     case one(Special)     case two }  var special1 = Special() special1.name = "Hello"  var special2 = Special() special2.name = "World" special2.special = special1  SpecialEnum.one(special1) == SpecialEnum.one(special2) //Well...? 

So if you want enums with associated values, you'll have to implement Equatable protocol in your enum by yourself:

enum NormalArg: Equatable {     case one(Int)     case two      static func ==(lhs: NormalArg, rhs: NormalArg) -> Bool {         switch (lhs, rhs) {         case (let .one(a1), let .one(a2)):             return a1 == a2         case (.two,.two):             return true         default:             return false         }     } } 
like image 177
xxtesaxx Avatar answered Sep 27 '22 21:09

xxtesaxx


The answer is Equatable Protocol.

Now let's see how it works.

Consider this enum for example:

enum Barcode {     case upca(Int, Int)     case qrCode(String)     case none } 

If we check the equatable operator == on the enum it will fail.

// Error: binary operator '==' cannot be applied to two Barcode operands Barcode.qrCode("code") == Barcode.qrCode("code") 

How to fix this using Equatable Protocol?

extension Barcode: Equatable { }  func ==(lhs: Barcode, rhs: Barcode) -> Bool {     switch (lhs, rhs) {     case (let .upca(codeA1, codeB1), let .upca(codeA2, codeB2)):         return codeA1 == codeA2 && codeB1 == codeB2      case (let .qrCode(code1), let .qrCode(code2)):         return code1 == code2      case (.None, .None):         return true      default:         return false     } }  Barcode.qrCode("code") == Barcode.qrCode("code") // true Barcode.upca(1234, 1234) == Barcode.upca(4567, 7890) // false Barcode.none == Barcode.none // true 
like image 42
aashish tamsya Avatar answered Sep 27 '22 23:09

aashish tamsya