Andrii Chernenko
Andrii Chernenko

Reputation: 10204

NOT condition in 'if case' statement

I have an enum:

enum E {
    case A, B, C(Int)
}

let a: E = .A

Here's how I would check if a equals .B

if case .B = a {
    // works fine
}

But how do I check the opposite condition? (a not equal .B)? Here's what I tried:

if case .B != a { // Variable binding in a condition requires an initializer
    // ...
}

if !(case .B = a) { // Expected ',' separator
    // ...
}

Of course, I could do it this way:

if case .B = a {
    // ...
} else {
    // put your code here
}

but this is awkward, as well as using switch statement. Are there any better options?


EDIT: The solution @Greg suggested works if cases do not have associated values, but if they do == operator needs to be overloaded. Sorry for not clarifying this in the first place.

Upvotes: 58

Views: 21963

Answers (5)

0-1
0-1

Reputation: 773

I saw the guard answer, and I though I could improve upon it.

Note how the do block is named. I mean, it works

i: do { guard case .B = a else {
    print("foo")
break i }}

Granted, this is much smaller: if case .B = a {} else { *** }


You can use this if you really want that ! operator

func cases<T: Equatable>(_ a: T,_ b: T) -> Bool { return a == b }
if cases(.B, a) {}
if !cases(.B, a) {}

Upvotes: -1

gebirgsb&#228;rbel
gebirgsb&#228;rbel

Reputation: 2397

Negating the .case statement is not possible. However you can use a normal comparison, like this:

if a != .B {

}

This is the most direct way to write it, in my opinion.

Upvotes: -6

epologee
epologee

Reputation: 11319

There aren't any answers yet mentioning the guard statement, introduced by Swift 2, which is a neat addition to the tools above and, if you ask me, the cleanest solution if you can live with the requirement to return from your function or closure within the else-block:

guard case .B = a else {
    // a does not match .B
    return
}

See Apple's "The Swift Programming Language (Swift 2.2): Statements" for more info.

Upvotes: 13

vacawama
vacawama

Reputation: 154721

This "answer" is nothing more than writing your awkward solution in a more compact manner. If you only care about the case when a value is not of a certain enum value, you could write it like this all in one line with the else immediately following the empty then clause:

enum E {
    case A, B(String), C(Int)
}

let a: E = .B("Hello")

if case .A = a {} else {
    print("not an A")
}

if case .B = a {} else {
    print("not a B")
}

if case .C = a {} else {
    print("not a C")
}

Upvotes: 39

Greg
Greg

Reputation: 25459

You are using single = sign which is an assignment operator. You have to use double == which is a comparison one and don't use case .A, use E.A is the right way to do that:

if E.A == a {
    // works fine
    print("1111")
}

if E.B != a {
    // works fine
    print("2222")
}

if E.B == a {
    // works fine
    print("3333")
}

Extended:

To make it works with associated values you have to implement Equatable protocol, example:

extension E: Equatable {}
func ==(lhs: E, rhs: E) -> Bool {
    switch (lhs, rhs) {
        case (let .C(x1), let .C(x2)):
            return x1 == x2
        case (.A, .A):
        return true

     default:
         return false
    }
}

Of course you have to handle all of the possibilities but I think you have an idea.

Extended:

I don't get your comment but this works for me fine:

enum E {
    case A, B, C(Int)
}

extension E: Equatable {}
func ==(lhs: E, rhs: E) -> Bool {
    switch (lhs, rhs) {
        case (let .C(x1), let .C(x2)):
            return x1 == x2
        case (.A, .A):
            return true
        case (.B, .B):
            return true

     default:
         return false
    }
}

let a: E = .A
let b: E = .B
let c: E = .C(11)

if E.A == a {
    // works fine
    print("aaa true")
}
if E.A != a {
    // works fine
    print("aaa false")
}

if E.B == b {
    // works fine
    print("bbb true")
}

if E.B == b {
    // works fine
    print("bbb false")
}

if E.C(11) == c {
    // works fine
    print("ccc true")
}

if E.C(11) != c {
    // works fine
    print("1 ccc false")
}

if E.C(22) != c {
    // works fine
    print("2 ccc false")
}

Upvotes: 8

Related Questions