guard Examples
This page was last reviewed on Aug 21, 2023.
Dot Net Perls
Guard. In Swift 5.8, guard is a special form of an if-statement—it ensures a condition is true. If the condition is not true, the guard must exit the current block.
A guard validates. A method may have invalid results if a parameter is not in the correct range. It is unsafe to use in this case. A guard can prevent logic errors later in the program.
First example. This example introduces a printArea func. In printArea we require both parameters to be greater than or equal to 1. Zero and negative values are invalid.
Here We use a guard statement with "x" and one with "y." A return prevents invalid arguments from being used.
Note Logically an area cannot be negative. And this program specially disallows empty areas.
Result The first call to printArea succeeds, as both arguments are valid. But the next two fail because of the guard clauses.
func printArea(x: Int, y: Int) { // Validate that "x" argument is valid. guard x >= 1 else { print("X invalid") return } // Validate "y" argument. guard y >= 1 else { print("Y invalid") return } // Print area. let area = x * y print(area) } // Call printArea. printArea(x: 5, y: 10) // Use invalid "X" then invalid "Y" arguments. printArea(x: 0, y: 1) printArea(x: 2, y: 0)
50 X invalid Y invalid
Must exit scope. A guard is more restricted than an if-statement. It is a special case of an if-statement. A guard must exit (with return, break) at the end of its list of statements.
Tip Before the "return," however, a guard can use any other logic like a print call. It can have multiple interior statements.
func test(size: Int) { guard size >= 10 else { print(1) } print(2) }
/.../main.swift:4:5: 'guard' body may not fall through, consider using 'return' or 'break' to exit the scope
Else error. The guard condition must have an else-keyword. We can think of a guard as an if-else with an empty "if" and a requirement that the control flow terminates in the "else."
Here The "else" keyword was omitted. The Swift compiler issues a compile-time error.
func multiplySize(size: Int) -> Int { guard size >= 0 { return 0 } return size * 2 }
/.../main.swift:2:21: Expected 'else' after 'guard' condition
Guard let. Consider this program. We introduce printSum, and this function has a guard statement. We bind the name "initial" to the result of the first property, which returns an optional.
And If the first elements in the Int array exits, we continue with printSum. Otherwise we return early.
func printSum(values: [Int]) { // Use optional binding in guard. // ... Return if no first element. guard let initial = values.first else { print("No initial element") return } // Print first element. print("First: \(initial)") // Sum elements. var sum = 0 for element in values { sum += element } // Print the sum. print("Sum: \(sum)") } // Use printSum func. printSum(values: []) printSum(values: [10, 11])
No initial element First: 10 Sum: 21
Loop continue, break. A guard can exit with a continue or break statement. So we can use guard conditions in loops (just like if-else statements).
Note In the while-loop we reach a continue statement unless the loop variable is even. So we skip odd numbers.
Odd, Even
Finally We reach a break statement if the "i" variable is greater than 10. This terminates the loop with a guard condition.
// Loop from 0 to infinity. var i = 0; while (true) { // Ensure we are on an even number. guard i % 2 == 0 else { i += 1 continue } // Ensure our number is less than or equal to 10. guard i <= 10 else { break } // Print our number. print("Number: \(i)") i += 1 }
Number: 0 Number: 2 Number: 4 Number: 6 Number: 8 Number: 10
FatalError. A guard must exit its containing scope. With fatalError we terminate the entire program. This counts as a valid exit condition.
Detail A program must be called with a certain starting value. With guard and fatalError we can ensure this.
var i = Int.max // This program must never be run with Int.max. guard i != Int.max else { // This is an exit condition like "return." fatalError("The Int.max cannot be used") } print("End")
fatal error: The Int.max cannot be used: file /.../main.swift, line 6 Program ended with exit code: 9
Throw. A guard block must exit somehow. This can be done with a throw-statement, which transfers control to the calling function. It enters an alternate control flow.
Here The start() func throws an ErrorCode.CodeZero unless its argument is 0. So we can only start() with a zero argument.
enum ErrorCode: Error { case CodeZero } func start(code: Int) throws { // This func must be called with argument 0 or it throws. // Use guard with "throw." guard code == 0 else { throw ErrorCode.CodeZero } // Begin. print("Start") } // Call start. try start(code: 900)
fatal error: Error raised at top level: Test.ErrorCode.CodeZero... (lldb)
Research. Why do we have guards in Swift? This is a construct that is meant to increase code readability. It makes code easier to validate and understand.
With a guard, we encode a branch that validates arguments or variables. It must return or break. So we use guard to terminate on invalid state before further problems appear.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Aug 21, 2023 (edit).
© 2007-2024 Sam Allen.