関数とクロージャ【Swiftイントロダクション#3】
関数
関数を宣言するにはfuncを使います。引数と戻り値のある関数を宣言するときは、->を使って関数の引数と戻り値を区切ります。
関数を呼び出す際は、関数名を使って呼び出します。引数のある関数を呼び出す時は、関数名に続けて括弧の中に引数のリストを記述します。
//関数の宣言
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
//関数を使う(greetはStringを2つとる関数なので2つStringを渡す)
greet(person: "Bob", day: "Tuesday")
関数を呼び出す際の引数名は、関数の宣言時に使ったのと同じ引数名が使われます。関数を呼び出す際に別の引数名を使いたい場合には、宣言時に引数名の前にラベルをつけます。ラベルが必要ない場合は_で省略することができます。
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
関数から複数の値を返したい場合はタプルを使います。タプルの要素には名前かインデックスでアクセスできます。
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.0)
このcalculateStatisticsという関数は渡された整数のアレーの中から、min(最小値)、max(最大値)、sum(合計値)を返します。
返された値にアクセスするには、statistics.sumのように変数名を使って取り出してもいいですし、取り出したい値をインデックスで指定して取り出すことも出来ます。(minが0、maxが1、sumが2なのでstatistics.0ではminを取り出しています。)
また、関数の引数にピリオド3つ( ... )をつけることで関数に任意の数の引数を渡すことが出来ます。渡された値は、配列として関数内で使われます。
func sumOf(numbers: Int...) -> Int {
//numbersは整数の配列
var sum = 0
for number in numbers {
sum += number
}
return sum
}
let result = sumOf(numbers: 42, 597,12)
print(result)
関数は入れ子構造にすることができます。ネストされた関数は親の関数が持っている変数にアクセスすることができます。関数が長くて複雑になってしまう時は、関数を入れ子構造にすることでコードを整理できます。
func returnFifteen() -> Int {
var y = 10
//関数もネストできる
func add() {
//ネストされた関数の中では、親であるreturnFifteen()が持っている変数であるyにアクセスできる。
y += 5
}
add()
return y
}
returnFifteen()
関数は返り値として別の関数を返すことができます。
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
上記の例では、incrementに、makeIncrementer()が代入されています。incrementが呼ばれるとmakeIncrementer()が実行されます。
makeIncrementer()の中を見てみると、返り値としてaddOne()を返すようになっています。なので、incrementが呼ばれると、makeIncrementer()が実行され、最終的にはmakeIncrementer()内にネストされたaddOne()が呼ばれます。
関数は引数に別の関数を取ることもできます。
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
//引数に別の関数をとる
hasAnyMatches(list: numbers, condition: lessThanTen)
上記のコードでは、hasAnyMatchesの2番目の引数(condition)にlessThanTen()という関数が渡されています。
hasAnyMatchesの中の、以下の部分のconditionというのはlessThanTen()のことなので、
if condition(item) {
}
ここでlessThanTen()の関数が呼ばれます。lessThanTenは渡された整数が10より小さければtrue、10以上であればfalseを返す関数です。
if condition(item)の引数であるitemが10より小さければこの分岐の中に入り、returnが返されます。
クロージャを記述する
関数は後から呼び出せるコードブロックであるという点において、クロージャの特別なケースと言えます。
クロージャ内では、クロージャが生成された時のスコープにおいてそのスコープ内の変数や関数にアクセスすることが出来ます。
また、実行時にそのスコープから外れてしまったとしても、生成時にアクセスできていた変数や関数にはアクセスが可能です。
波括弧({})を使うことで名前を付けずにクロージャを記述することができます。inを使って、引数と返り値の型を関数の中身(実行内容の記述部分)から分けます。
var numbers = [20, 19, 7, 12]
//{}を使うことで、名前をつけずにクロージャを記述できる。
numbers.map({
(number: Int) -> Int in
let result = 3 * number
print(result)
return result
})
クロージャをもっと簡潔に書く方法がいくつかあります。
クロージャがデリゲートのコールバックの場合など、クロージャの型がもうすでに分かっている場合には引数の型か返り値の型、もしくは両方を省くことができます。クロージャが一文の場合は、明示的に記述しなくても、その文の結果を返します。
//return を書かなくても文の結果を返す
let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)
名前の代わりに数字でも引数にアクセスすることができます。
数字でアクセスする方法は、短いクロージャにとても便利です。関数の最後の引数として渡されたクロージャは括弧()のすぐ後ろに配置されます。もしクロージャが関数の唯一の引数である場合は、括弧()も省略することができます。
//数字を大きい順に並べる
let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)
次回は【オブジェクトとクラス】について解説します!
今までのSwiftイントロダクション
#1 シンプルな値
#2 制御フロー
この記事が気に入ったらサポートをしてみませんか?