Functions and closures
Chapter 4 printed Pack tea and Pack milk inside a loop. When another
part of the script needs that wording, give it a name:
func pack(item: String) -> String {
return "Pack \(item)"
}
func twice(_ count: Int) -> Int {
return count * 2
}
print(pack(item: "tea"))
print(pack(item: "milk"))
print("Twice: \(twice(3))")
Pack tea
Pack milk
Twice: 6
func defines a function; the parentheses hold its parameters. In
pack(item: String), item is the name inside the function and the label
at the call. The -> String promises a result, which return sends back.
twice(_ count: Int) skips the call-site label with _, so the call is
twice(3). Inside, the parameter is still called count.
A parameter cannot be reassigned inside its function. If a calculation needs
a changing working value, start a local var from the parameter. That keeps
the input name steady while you work.
Leave early
A portion count for zero guests needs no calculation:
func portions(for guests: Int) -> Int {
guard guests > 0 else {
return 0
}
return guests * 2
}
print("Three guests: \(portions(for: 3))")
print("No guests: \(portions(for: 0))")
Three guests: 6
No guests: 0
The external label for makes the call read portions(for: 3); the function
uses guests inside. If there are no guests, the guard takes its required
else branch and returns 0. Otherwise execution carries on below the
brace. The condition must be a Bool, just as it was for if in chapter 3.
The failing branch must leave the function, rather than slipping through to
return guests * 2. We’ll meet guard with an optional value in chapter 7;
no optional is needed for this check.
A function you can hand over
Functions can take other functions as inputs. apply takes a number and a
function to use on it:
func apply(_ number: Int, using transform: (Int) -> Int) -> Int {
return transform(number)
}
let offset = 2
let addOffset: (Int) -> Int = { number in number + offset }
print("Offset: \(apply(4, using: addOffset))")
print("Double: \(apply(4) { number in number * 2 })")
Offset: 6
Double: 8
(Int) -> Int describes a function that takes one Int and returns one
Int. The closure between braces is a value of that type. Because
addOffset has a type annotation, number gets its type from the context;
in separates the parameter from the calculation. A single-expression
closure returns that expression. It can also read offset, the let binding
beside it.
The second call puts its final closure after apply(4). Those braces supply
an argument; apply calls the closure with its number. The first call uses
the same argument position, but passes a named value as using: addOffset.
Here offset stays fixed. We’ll leave changing captured variables for later.