I am confused about the definition of a code block or of 'scope'. Apple docs for guard say this: the else block of a guard statement...
"must transfer control to exit the code block in which the guard statement appear."
Other online sources say the guard statement must exit the 'scope' in which it exists.
So take the example code below:
func testGuardControlFlow () {
let x = 2
let y = 2
func embededFunc () {
if y == 2 {
guard x == 1 else {
print("oops, number is not 1")
return
}
print ("from in embededFunc")
}
print ("I still want this to print even if x != 1")
}
embededFunc()
print("Great, return still allows this to be printed.")
}
testGuardControlFlow()
According to my current understanding of 'scope', the code
if y == 2 {....}
creates a new scope, namely between { }. And given this assumption, guard would merely escape that scope. But that is not the case. Guard in this instance escapes from the function it is placed in, irrespective of whether it is buried in an if clause.
Am I completely misunderstanding what 'scope' means? Does scope mean the code contained in a method? If so, what is the correct term for the 'space' that exists within an if statement?
Guard statements in Swift allow us to implement checks into our code that prevents the current scope from continuing. When writing code, we often have certain required conditions before continuing a method. An example can be unwrapping an optional input field before submitting a form.
Guard statements MUST transfer control away from its enclosing scope, in order to leave the scope it is written in. In this case, it must leave the function, via the “return” keyword.
The syntax of the guard statement is: guard expression else { // statements // control statement: return, break, continue or throw. } Note: We must use return , break , continue or throw to exit from the guard scope.
A guard statement is capable to transfer the flow of control of a program if a certain condition(s) aren't met within the program. Or we can say, if a condition expression evaluates true, then the body of the guard statement is not executed.
It is totally possible to do what you envision, it just happens to not be what that particular code does. return
always exits a method, not the local scope. To do what you wish, you can use a label, and break
:
func testGuardControlFlow () {
let x = 2
let y = 2
func embededFunc () {
breakLabel:
if y == 2 {
guard x == 1 else {
print("oops, number is not 1")
break breakLabel
}
print ("from in embededFunc")
}
print ("I still want this to print even if x != 1")
}
embededFunc()
print("Great, return still allows this to be printed.")
}
testGuardControlFlow()
To add on to vadian's answer:
guard
forces you to exit the scope using a control transfer statement. There are 4 available to you:
return
and throw
both exit the function/methodcontinue
can be used within loops (while
/for
/repeat-while
)break
can be used in loops (while
/for
/repeat-while
) to exit the immediate scope. Specifying a label to break to will allow you to exit multiple scopes at once (e.g. breaking out of nested loop structure). When using a label, break
can also be used in if
scopes.Additionally, you may exit the scope by calling a function that returns Never
, such as fatalError
.
Your understanding of the term scope is absolutely correct. Basically it's the space between two (balanced) braces.
The description to exit the code block in the documentation is the most accurate.
To exit a guard
statement you can use the control transfer statements return
, break
, continue
, or throw
.
return
and throw
exits the whole function or method.continue
and break
exits the current scope (for example switch
, for
or while
).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