(Updated for Swift >=3)
"Double optionals" can be useful, and the Swift blog entry "Optionals Case Study: valuesForKeys" describes an application.
Here is a simplified example:
let dict : [String : String?] = ["a" : "foo" , "b" : nil]
is a dictionary with optional strings as values. Therefore
let val = dict[key]
has the type String??
aka Optional<Optional<String>>
. It is .none
(or nil
)
if the key is not present in the dictionary, and .some(x)
otherwise. In the second
case, x
is a String?
aka Optional<String>
and can be .none
(or nil
)
or .some(s)
where s
is a String.
You can use nested optional binding to check for the various cases:
for key in ["a", "b", "c"] {
let val = dict[key]
if let x = val {
if let s = x {
print("(key): (s)")
} else {
print("(key): nil")
}
} else {
print("(key): not present")
}
}
Output:
a: foo
b: nil
c: not present
It might be instructive to see how the same can be achieved with pattern matching
in a switch-statement:
let val = dict[key]
switch val {
case .some(.some(let s)):
print("(key): (s)")
case .some(.none):
print("(key): nil")
case .none:
print("(key): not present")
}
or, using the x?
pattern as a synonym for .some(x)
:
let val = dict[key]
switch val {
case let (s??):
print("(key): (s)")
case let (s?):
print("(key): nil")
case nil:
print("(key): not present")
}
(I do not know a sensible application for more deeply nested optionals.)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…