Unwrap Swift optional value in Switch case
source link: https://sarunw.com/posts/optional-binding-switch-case/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
When you want to unwrap an optional value in Swift, you probably use if let
or guard let
syntax.
let name: String? = "Sarunw"
if let name = name {
print("Hello, \(name)!")
} else {
print("Hello, World!")
}
But you might not be aware that you can also do this in a switch
statement.
Unwrap optional value the wrong way
Unwrap optional value with switch case
is a bit tricky if you aren't familiar with the language.
First, let's try to unwrap it the wrong way.
let name: String? = "Sarunw"
switch name {
case let unwrappedName:
print("Hello, \(unwrappedName)!")
default:
print("Hello, World!")
}
If you try to do it like this, you will get two warnings.
You can't unwrap an optional value like this.
- The first one is because our
unwrappedName
variable that we expected it to be unwrapped is still an optional value. - The second warning one telling you that the
default
case wouldn't be reached.
As you can see, we can't use case let
[1] to unwrap an optional value in switch case
. That would just bind the same optional value to a new variable[1:1].
Since the first case just takes any value and reassigns it to a new variable, there is no more case to handle. And that is a reason why the default
case won't be reached.
Optional Binding using a switch statement
You have to know one fact to unwrap an optional value using a switch
statement. That is, an optional is just an enum.
Optional Enum
Optional
is an enumeration with two cases.none
represents an absence of a value (nil
).some(Wrapped)
represents a presence of a value stored as an associated value.
enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)
}
Since it is an enum with an associated value, we can get an unwrapped optional value by reading the associated value from the .some
case, the same way we do with a normal enum.
let name: String? = "Sarunw"
switch name {
case .none:
print("Hello, World!")
case .some(let unwrappedName):
print("Hello, \(unwrappedName)!")
}
Optional Pattern
There is also a special pattern for direct matches against a value wrapped in a .some(Wrapped)
called Optional Pattern.
You can use an Optional pattern by putting a question mark (?
) right behind a variable name.
Optional patterns are syntactic sugar for Optional enumeration case patterns. So, the following are equivalent:
let name: String? = "Sarunw"
switch name {
case .none:
print("Hello, World!")
case .some(let unwrappedName):
print("Hello, \(unwrappedName)!")
}
switch name {
case .none:
print("Hello, World!")
// Optional Pattern
case let unwrappedName?:
print("Hello, \(unwrappedName)!")
}
case .some(let unwrappedName)
is equivalent to case let unwrappedName?
.
Conclusion
Unwrap optional values using a switch
statement might seem overcomplicated for simple cases that I show in this article. But you would find a place for it in more complex cases.
Here is an example of an optional as an associated value of another enum.
let result: Result<String?, Error> = .success("Response")
switch result {
case .success(let str):
// 1
if let str = str {
print("Success: \(String(str))")
} else {
print("Success with no Data")
}
case .failure(let error):
print("Failure: \(error.localizedDescription)")
}
switch result {
// 2
case .success(let str?):
print("Success: \(String(str))")
// 3
case .success(.none):
print("Success with no Data")
case .failure(let error):
print("Failure: \(error.localizedDescription)")
}
- In the first case, 1, we unwrap an optional associated value using
if let
. - In the second case, we use what we learn and split
.success
into two cases. One for a success case with value 2, another one without the value 3.
Another example where this might be useful is when we have to control the flow based on more than one optional value.
In this example, I try to print a proper message based on two optional values, first name and last name.
let firstName: String? = "John"
let lastName: String? = nil
if let firstName = firstName,
let lastName = lastName {
print("\(firstName) \(lastName)")
} else if let firstName = firstName {
print("Only \(firstName)")
} else if let lastName = lastName {
print("Only \(lastName)")
} else {
print("No name")
}
switch (firstName, lastName) {
case let (firstName?, lastName?):
print("\(firstName) \(lastName)")
case let (firstName?, .none):
print("Only \(firstName)")
case let (.none, lastName?):
print("Only \(lastName)")
case (.none, .none):
print("No name")
}
There is nothing wrong with if else
, but I usually find this kind of comparing easier to understand on a switch
statement.
The thing we learned in this article is just a tool. You have to judge for yourself when to use it. There is no right or wrong.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK