Swift: testing against optional value in switch case

SwiftEnumsSwitch StatementOptional

Swift Problem Overview


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).

Swift Solutions


Solution 1 - Swift

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")        
}

Solution 2 - Swift

As of Xcode 7, “a new x? pattern can be used to pattern match against optionals as a synonym for .some(x)”. This means that in Swift 2 and later the following variation of rintaro's answer will work as well:

let knownValue = 5

switch someOptional {
case knownValue?:
	// Contents of someOptional are knownValue, defined above.
case let otherValue?:
	// Contents of someOptional are *any* non-nil value not already tested for.
	// Unwrapped contents are assigned to otherValue for use inside this case.
default:
	// someOptional is nil.
}

Solution 3 - Swift

In Swift 4 you can use Optional : ExpressibleByNilLiteral of Apple to wrappe optional

https://developer.apple.com/documentation/swift/optional

Example

enum MyEnum {
    case normal
    case cool
}

some

let myOptional: MyEnum? = MyEnum.normal

switch smyOptional {
    case .some(.normal): 
    // Found .normal enum
    break

    case .none: 
    break
    
    default:
    break
}

none

let myOptional: MyEnum? = nil

switch smyOptional {
    case .some(.normal): 
    break

    case .none: 
    // Found nil
    break
    
    default:
    break
}

default

let myOptional: MyEnum? = MyEnum.cool

switch smyOptional {
    case .some(.normal): 
    break

    case .none: 
    break
    
    default:
    // Found .Cool enum
    break
}

Enum with value

enum MyEnum {
    case normal(myValue: String)
    case cool
}

some value

let myOptional: MyEnum? = MyEnum.normal("BlaBla")

switch smyOptional {
case .some(.normal(let myValue)) where myValue == "BlaBla":
    // Here because where find in my myValue "BlaBla"
    break
    
// Example for get value
case .some(.normal(let myValue)):
    break
    
// Example for just know if is normal case enum
case .some(.normal):
    break
    
case .none:
    break
    
default:
    
    break
}

Solution 4 - Swift

You can explicitly mention all cases along with nil as an additional case to handle the optional:

switch optionalEnumValue {
case .caseOne:
    break
case .caseTwo:
    break
case .caseN:
    break
case nil:
    break
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGeorge WSView Question on Stackoverflow
Solution 1 - SwiftrintaroView Answer on Stackoverflow
Solution 2 - SwiftSlipp D. ThompsonView Answer on Stackoverflow
Solution 3 - SwiftYannStephView Answer on Stackoverflow
Solution 4 - SwiftAJRView Answer on Stackoverflow