Reputation: 25632
Optional chaining lets us make decisions on the existence of objects:
var text : String?
let len = text?.lengthOfBytes(using: .utf8) ?? 0
Which will always set len
to an integer.
Is something similar possible for non-optional function arguments? Consider the following example, which already is less elegant with the ternary operator.
func length(text: String) -> Int {
return text.lengthOfBytes(using: .utf8)
}
var text : String?
let len = (text != nil) ? length(text!) : 0
If we keep chaining, it easily gets a mess (and this is what I am actually looking at):
let y = (arg!= nil) ? (foo?.bar(arg!) ?? 0) : 0 // how to improve on this?
Besides, it also starts to get redundant, defining the default value twice.
Is there any more concise solution to the last line?
Upvotes: 1
Views: 795
Reputation: 58
The map
method is the best approach for this. flatMap
may also be of interest.
func length(text: String) -> Int {
return text.lengthOfBytes(using: .utf8)
}
var text : String?
let len = text.map(length) ?? 0
If you have multiple arguments, you can pretty easily write a function (A?, B?) -> (A, B)?
.
Upvotes: 1
Reputation: 93151
You don't have to limit yourself to optional chaining. Swift provides other language constructs to express this clearly:
let y: Int
if let arg = arg, let foo = foo {
y = foo.bar(arg)
} else {
y = 0
}
Upvotes: 0
Reputation: 15512
Take into account that usage of the ??
will do impact on compilation time.
In example that you describe, personally I like to use extensions that are clear to use.
extension Optional where Wrapped == String {
func unwrappedLengthOfBytes(using: String.Encoding) -> Int {
guard let text = self else {
return 0
}
return text.lengthOfBytes(using: .utf8)
}
}
Usage:
var text : String?
text.unwrappedLengthOfBytes(using: .utf8)
Upvotes: 0