Search code examples
swiftenumsswitch-statementoption-type

Swift: testing against optional value in switch case


In Swift, how can I write a case in a switch statement that tests the value being switched against the contents of an optional, skipping over the case if the optional contains nil?

Here's how I imagine this might look:

let someValue = 5
let someOptional: Int? = nil

switch someValue {
case someOptional:
    // someOptional is non-nil, and someValue equals the unwrapped contents of someOptional
default:
    // either, someOptional is nil, or someOptional is non-nil but someValue does not equal the unwrapped contents of someOptional
}

If I just write it exactly like this, the compiler complains that someOptional is not unwrapped, but if I explicitly unwrap it by adding ! to the end, I of course get a runtime error any time someOptional contains nil. Adding ? instead of ! would make some sense to me (in the spirit of optional chaining, I suppose), but doesn't make the compiler error go away (i.e. doesn't actually unwrap the optional).


Solution

  • Optional is just a enum like this:

    enum Optional<T> : Reflectable, NilLiteralConvertible {
        case none
        case some(T)
    
        // ...
    }
    

    So you can match them as usual "Associated Values" matching patterns:

    let someValue = 5
    let someOptional: Int? = nil
    
    switch someOptional {
    case .some(someValue):
        println("the value is \(someValue)")
    case .some(let val):
        println("the value is \(val)")
    default:
        println("nil")
    }
    

    If you want match from someValue, using guard expression:

    switch someValue {
    case let val where val == someOptional:
        println(someValue)
    default:
        break
    }
    

    And for Swift > 2.0

    switch someValue {
    case let val where val == someOptional:
        print("matched")
    default:
        print("didn't match; default")        
    }