I'm trying to make a simple if-let statement with more than one value. The if
block should be executed only if all optional vars are non-nil, plus they should be assigned to the new let-vars (constants?) that live only inside the if
block, just like the normal single-assignment if-let.
var a: String? = "A"
var b: String? // nil
if let (m, n) = (a, b) {
println("m: \(m), n: \(n)")
} else {
println("too bad")
}
// error: Bound value in a conditional binding must be of Optional type
// this of course is because the tuple itself is not an Optional
// let's try that to be sure that's the problem...
let mysteryTuple: (String?, String?)? = (a, b)
if let (m, n) = mysteryTuple {
println("m: \(m), n: \(n)")
} else {
println("too bad")
}
// yeah, no errors, but not the behavior I want (printed "m: A, n: nil")
// and in a different way:
if let m = a, n = b {
println("m: \(m), n: \(n)")
} else {
println("too bad")
}
// a couple syntax errors (even though 'let m = a, n = b'
// works on its own, outside the if statement)
Is this even possible? If not (which I'm guessing), do you think Apple will (or should) implement this in the future?
So, use if let if you just want to unwrap some optionals, but prefer guard let if you're specifically checking that conditions are correct before continuing.
The “if let” allows us to unwrap optional values safely only when there is a value, and if not, the code block will not run. Simply put, its focus is on the “true” condition when a value exists.
Overview. We can assign values to multiple variables at once in a single statement in Swift. We need to wrap the variables inside a bracket and assign the values using the equal sign = . The values are also wrapped inside a bracket.
This is probably evident by now, but your quest for this expected functionality can end with the release of Swift 1.2.
From the swift blog: https://developer.apple.com/swift/blog/?id=22
More powerful optional unwrapping with if let — The if let construct can now unwrap multiple optionals at once, as well as include intervening boolean conditions. This lets you express conditional control flow without unnecessary nesting.
The short of it though, is that you can now do what you are asking, in addition to constraining the values with where clauses.
if let a = foo(), b = bar() {
}
Before deciding whether it is possible or not, consider why if - let ...
conditionals work with a single optional value: the reason this code compiles
if let constVar = testVar {
...
}
is that all optional types conform to the LogicalValue
protocol, which handles the null checking of the optional value.
This explains why your trick with an optional tuple did not work either: the implementation of the LogicalValue
checked if the tuple itself is non-null, ignoring its components. The logic behind Apple's decision is clear: rather than making an exception for tuples when all their element types are optional, they took the uniform approach, and treated the tuple in the same way that they treat other optional types.
Of course, implementing the logic that you are trying to implement is easy with an additional line of code:
if a != nil && b != nil {
let (m, n) = (a!, b!)
println("m: \(m), n: \(n)")
} else {
println("too bad")
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With