関数とクロージャ【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)

スクリーンショット

関数は任意の数の引数をとって、配列を作ることができます。

func sumOf(numbers: Int...) -> Int {
    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)

スクリーンショット

関数は引数に別の関数を取ることもできます。

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)

スクリーンショット

関数はクロージャの特別なケースと言えます。後からコードブロックを呼び出すことができます。クロージャ内のコードはクロージャが生成された時のスコープにある変数や関数にアクセスできます。また、実行時にそのスコープから外れてしまったとしても生成時にアクセス可能だった変数や関数にアクセスすることができます。波括弧({})を使うことで名前を付けずにクロージャを記述することができます。inを使って引数と返り値の型を本体のコードから分けます。

var numbers = [20, 19, 7, 12]
//{}を使うことで、名前をつけずにクロージャを記述できる。
numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    print(result)
    return result
})

スクリーンショット

クロージャをもっと簡潔に書く方法がいくつかあります。クロージャがデリゲートのコールバックの場合など、クロージャの型がもうすでに分かっている場合には引数の型か返り値の型、もしくは両方を省くことができます。クロージャが一文の場合は、明示的に記述しなくても、その文の値を返します。

let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)

スクリーンショット
名前の代わりに数字でも引数にアクセスすることができます。数字でアクセスする方法は、短いクロージャにとても便利です。関数の最後の引数として渡されたクロージャは括弧()のすぐ後ろに配置されます。もしクロージャが関数の唯一の引数である場合は、括弧()も省略することができます。

//数字を大きい順に並べる
let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)

スクリーンショット