Reputation: 2697
The Swift guard statement allows you to unwrap optionals to a new constant and do an early return if the assignment fails.
var someString:String? = "hello"
...
...
guard let newString = someString
else {
return
}
...
If I want to unwrap an optional and set it to a pre-defined non-optional variable, I've been first unwrapping to the new constant (newString) and then setting the non-optional variable after the guard statement like this:
var someString:String? = "hello"
var nonOptionalString:String = "bonjour"
...
...
guard let newString = someString
else {
return
}
nonOptionalString = newString
...
Is there a way to set a pre-defined, non-optional var within the condition of the guard statement without creating a new constant? Something like the following (which doesn't work)?
var someString:String? = "hello"
var nonOptionalString:String = "bonjour"
...
...
guard nonOptionalString = someString
else {
return
}
...
If something like this isn't possible, is there an underlying philosophy behind the Swift language design or technical reason as to why this doesn't exist?
Upvotes: 3
Views: 2325
Reputation: 437442
I would just test for nil
and then force unwrap when I know it's not:
var someString: String? = "hello"
let nonOptionalString: String // note, you don't have to initialize this with some bogus value
guard someString != nil else { return }
nonOptionalString = someString!
Or if someString
was a parameter to some method or closure, you can unwrap in the guard
statement using the same variable name, simplifying life even more:
func foo(someString: String?) {
guard let someString = someString else { return }
// now I can just use local `someString`, which is not optional anymore
}
If you're desperate to unwrap and exit-if-nil
in a single statement, you could theoretically write a function to unwrap if it can or throw an error if it can't:
extension Optional {
enum OptionalError: Error {
case unwrapFailed
}
func unwrap<T>() throws -> T {
if self == nil { throw OptionalError.unwrapFailed }
return self as! T
}
}
Then you can do:
do {
firstNonOptional = try firstOptional.unwrap()
secondNonOptional = try secondOptional.unwrap()
thirdNonOptional = try thirdOptional.unwrap()
} catch {
return
}
I think that's horrible overkill, but if you're desperate to distill it down to one line per unwrap, that's one way to do it.
Upvotes: 3
Reputation: 631
There are two ways I would go around doing this.
guard let someString = someString else { return }
This just checks the value, with the same variable name.
guard someString != nil else { return }
Doing this second one, you can even declare it with a bang(!) it will be "pre-defined" to a "non-optional" in a way.
So now you could declare it like:
var someString:String! = "hello"
I think you are looking for exactly this.
EDIT: And now you can use your own example.
guard someString != nil, nonOptional == someString else { return }
Upvotes: 1
Reputation: 534958
If the point is to make the assignment only if the assignment is possible, write:
nonOptionalString = someString ?? nonOptionalString
If you really also need the return
if the assignment is impossible, then just write an if/else clause:
if someString != nil {
nonOptionalString = someString!
} else {
return
}
In other words, stop trying to be so fancy and just say what you mean.
Upvotes: 0