When did `guard let foo = foo` become legal?
TL;DR
guard let foo = foo
is legal if foo
was defined in another scope.
The example from your linked question:
func test()
{
let a: Int? = 1
guard let a = a else{
return
}
print("a = \(a)")
}
still doesn't work because the guard
statement is trying to create another variable a
in the same scope.
This example:
//Test of using guard to create an unwrapped version of a var, like if let
func guardTest(_ viewController: UIViewController?) -> UIViewController? {
// Check if the current viewController exists
print(String(describing: viewController))
guard let viewController = viewController else {
return nil
}
print(String(describing: viewController))
return viewController
}
works for the same reason that this does:
func test(a: Int)
{
print(type(of: a)) // Int
let a = 3.14
print(type(of: a)) // Double
}
The parameter to the function is defined in a different scope, so Swift allows you to create a local variable with the same name.
Why isn't guard let foo = foo valid?
The reason you can't do this:
func test()
{
let a: Int? = 1
guard let a = a else{
return
}
print("a = \(a)")
}
is because guard
creates the new variable in the same scope, thus you have two variables called a
in the same scope. One is an Int
and the other is an Int?
. That is not allowed.
The error that you get Definition conflicts with previous value is exactly the same as if you had done this:
func test()
{
let a: Int? = 1
let a = a!
}
Compare that with:
func test()
{
let a: Int? = 1
if let a = a {
print("a = \(a)")
}
}
In this case, the new variable a
which is an Int
exists only in the new scope of the if
's then clause, so this works.
From the comments:
But I submit to you that the section of code after the closing brace
and to the end of the enclosing scope is actually an inner scope.
I can understand that you would like it to be so, but it isn't. If that were the case, then you could do this, but it too gives an error:
func test()
{
let a: Int? = 1
guard let b = a else{
return
}
print("b = \(b)")
let a = 5 // Definition conflicts with previous value
print("a = \(a)")
}
The beauty of guard
is that it doesn't create new scopes and you avoid creating the pyramid of death that results when you repeatedly use if let
to unwrap optionals (and in the process create new scopes).
See the follow-up question
When did guard let foo = foo become legal? for more insight on this topic.
guard let found nil
selectedRooms.text
cannot return nil
.
A UITextField
and UITextView
always returns a String
value. An empty String
(""
) is returned if there is no text in the UITextField and UITextView
. That's the reason else
part is not executing and rooms
value is nil
.
Now, in the below statement you're force-unwrapping(!
) the rooms
.
x = Int(ceil(sqrt(Double(rooms!))))
But, since the rooms
is nil
, so forcefully unwrapping it is throwing runtime exception.
Solution:
You need to add an empty check as well for the else
part to take effect, i.e.
guard let numberOfRooms = selectedRooms.text, !numberOfRooms.isEmpty else { //here...
return selectedRooms.placeholder = "type something"
}
About guard let syntax
Try this in playground:
guard let f = e else { fatalError("s is nil") }
Hope it helps!
Are multiple lets in a guard statement the same as a single let?
These are different in Swift 3. In this case:
guard let foo = bar, let qux = taco else {
you're saying "optional-unwrap bar into foo. If successful, optional unwrap taco into qux. If successful continue. Else ..."
On the other hand this:
guard let foo = bar, qux = taco else {
says "optional-unwrap bar into foo. As a Boolean, evaluate the assignement statement qux = taco
" Since assignment statements do not return Booleans in Swift, this is a syntax error.
This change allows much more flexible guard
statements, since you can intermix optional unwrapping and Booleans throughout the chain. In Swift 2.2 you had to unwrap everything and then do all Boolean checks at the end in the where
clause (which sometimes made it impossible to express the condition).
Although use of guard let , not unwrapped error
You have to optional downcast all dictionaries to the proper type
guard let json = try NSJSONSerialization.JSONObjectWithData(tickerData, options: []) as? [String:AnyObject] else { return nil }
guard let tableauUn = json["result"] as? [String:AnyObject] else {return nil }
guard let tableauDeux = tableauUn["XXBTZEUR"] as? [String:AnyObject] else { return nil}
and the final value
let prix = tableauDeux["o"] as? String
How to write this condition using guard let
This is the equivalent guard
statement:
guard (self.fromLocation != nil && self.toLocation != nil) || !self.key.isEmpty else {
return
}
Explanation:
I arrived at this by taking the statement of when we want to return
:
(self.fromLocation == nil || self.toLocation == nil) && self.key.isEmpty
and negating it to get when we want to stay:
!((self.fromLocation == nil || self.toLocation == nil) && self.key.isEmpty)
Applying De Morgan's law !(A && B) <==> !A || !B
:
!(self.fromLocation == nil || self.toLocation == nil) || !self.key.isEmpty
and then applying De Morgan's law !(A || B) <==> !A && !B
:
(!(self.fromLocation == nil) && !(self.toLocation) == nil) || !self.key.isEmpty
and then noting that !(A == nil) <==> A != nil
gives us the final result:
(self.fromLocation != nil && self.toLocation != nil) || !self.key.isEmpty
Note:
You said you wanted to do this with guard let
, but that doesn't make sense since you stated that you are willing to continue if one or both variables are nil
as long as key is not empty, so it isn't possible to guarantee that the unwrapped variables will exist after the guard
statement.
Related Topics
Fixing Nsurlconnection Deprecation from Swift 1.2 to 2.0
How to Display Data from Firebase Faster
Lesser Than or Greater Than in Swift Switch Statement
@Noescape Attribute in Swift 1.2
How to Create Swift Class for Category
How to Make Class Methods/Properties in Swift
Why Use Required Initializers in Swift Classes
Find Difference in Seconds Between Nsdates as Integer Using Swift
What's the Difference Between Struct Based and Class Based Singletons
Swift 2/iOS 9 - Libz.Dylib Not Found
Any Way to Iterate a Tuple in Swift
Swift Protocol Error: 'Weak' Cannot Be Applied to Non-Class Type
Show Am/Pm in Capitals in Swift
Firebase Instanceid.Instanceid().Token() Method Is Deprecated