Swift: testing against optional value in switch case
Solution 1
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
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
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
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
}
Related videos on Youtube
George WS
Coding in class, studying SICP over breaks, and working on iOS apps whenever I can.
Updated on October 29, 2021Comments
-
George WS over 2 years
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 timesomeOptional
containsnil
. 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). -
Martin R over 7 yearsThe question is about matching a non-optional value against an optional, this answer is the other way around.
-
Slipp D. Thompson over 7 yearsTrue, however this answer was originally written by the OP as an update to the question so to him it was irrefutably a viable solution; I just moved it to a community wiki answer. Perhaps @GeorgeWS can clarify as to why switching the switch & case args works for his use-case?
-
mfaani over 6 yearsI'm a bit lost. what's the difference between your first two cases?
someValue?
is some other defined value, butcase let val?
is just the safe unwrapped version ofsomeOptional
?! -
Slipp D. Thompson over 6 years@Honey It's not a real-world code example; it's simply a variation on rintaro's answer. So go ask him/her that question— my answer is functionally equivalent to the code in his/hers. If you were to ask rintaro though, I believe the answer would be 1. it mirrors what's in the linked Apple docs; 2. it only demonstrates the syntax; it does not accomplish a distinct calculation or business logic goal.
-
Slipp D. Thompson over 6 years@Honey Also, rintaro's answer was originally written for Swift 1.x and updated for Swift 2. It's possible that the version without
let
no longer compiles. I can't remember right now why that would've worked back in the day. -
George WS over 4 years@Honey I think you're exactly right about the first two cases—the difference is that
someValue
was presumed to be a specific, known value we were checking for, whereasval
was just any other non-optional value thatsomeOptional
might contain. I updated the code sample to make this more clear (renamedsomeValue
→knownValue
andval
→otherValue
, showedknownValue
being assigned before theswitch
, and added more precise comments). Thanks for pointing out the confusing-ness of this—*totally* see why it was confusing, looking back at it a year+ later! 😂 -
George WS over 4 years@SlippD.Thompson The short answer to why this worked for me is… I don't remember. 🤷🏼♂️ Longer answer, looking back—I think switching the
switch
andcase
s worked here for me because I was able to find out what I wanted to know with either method of constructing theswitch
statement. Looking at the original question, I wanted to know if…// someOptional is non-nil, and someValue equals the unwrapped contents of someOptional
…which is true both in the first case of my imagined-switch in the question, and in the analogous second case here (case let otherValue?
). -
pkamb over 3 yearsYou mention
ExpressibleByNilLiteral
but then that is not actually used in the enum declarations etc. What is that?