Reputation: 5710
I am trying to do something that would logically look like this:
if text == "" || let i = Int(text) where i < 2 {
// do something; don't care about the value of i
}
Of course this isn't a valid condition -- what would the value of i
be if text == ""
is the part that holds? But, since I'm only interested in the value of i
inside the where
clause, I was hoping there is a nice way of achieving the same effect, namely executing the same closure if either condition holds. My current solution is to extract the closure and call it from two separate if
blocks, but that's pretty hairy-looking.
Upvotes: 2
Views: 1503
Reputation: 5710
Perhaps a more "Swifty" way to handle optional values is with map
. Essentially, map
ping an optional value gives you an unwrapped value in your closure, which you can then modify to return what you need. Outside the closure, you will receive either the modified value, or nil if the original optional was nil.
let optInt: Int? = 1 // or nil
let incremented: Int? = optInt.map { $0 + 1 }
// If optInt isn't nil, its incremented value is returned by map.
// If it is nil, map just returns nil.
So to solve my problem, I could do:
if text == "" || Int(text).map({$0 < 2}) ?? false {
// If text has an Int value, the map closure will return
// whether that value is less than 2.
// Else, map will return nil, which we coalesce to false.
}
Upvotes: 0
Reputation: 80811
If you're doing this kind of comparison regularly, you could create your own operator in order to compare an optional with a given closure representing your condition for success. If the unwrapped value meets the condition, it'll return true – else false.
For example:
infix operator ?& {precedence 130 }
func ?&<T>(lhs: T?, @noescape rhs:(T)->Bool) -> Bool {
return lhs != nil ? rhs(lhs!) : false
}
...
if text == "" || Int(text) ?& {$0 < 2} {
print("valid")
} else {
print("invalid")
}
You could also overload the existing <
operator to do this, but this may impact already existing code that relies on nil
being less than a non-optional value.
func <<T:Comparable>(lhs: T?, rhs:T) -> Bool {
return lhs != nil ? (lhs! < rhs) : false
}
...
if text == "" || Int(text) < 2 {
print("valid")
} else {
print("invalid")
}
Upvotes: 3
Reputation: 57124
The equivalent to your code example would be:
if text == "" || Int(text) ?? 2 < 2 {
print("valid")
// do your previous "something
} else {
print("invalid")
}
which yields
"" -> valid
"1" -> valid
"2" -> invalid
"abc" -> invalid
Upvotes: 3