欠如

来世は貝になりたい

Swiftの文法について復習してみる Functions and Closures

前回に引き続きツアーをやります

前回がfor in がwhile repeatなど制御などがテーマが今回は第三回目ということでテーマがFunctions and Closures(関数とクロージャ)となります。

クロージャ(クロージャー、英語: closure)、関数閉包はプログラミング言語における関数オブジェクトの一種。
いくつかの言語ではラムダ式や無名関数で実現している。
引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。
関数とそれを評価する環境のペアであるともいえる。
この概念は少なくとも1960年代のSECDマシンまで遡ることができる。
まれに、関数ではなくとも、環境に紐付けられたデータ構造のことをクロージャと呼ぶ場合もある。
クロージャをサポートした言語のコーディングでは、関数の中に関数を定義することができる。
その際に、外側の関数で宣言された変数を内側の関数で操作することができる。主な利点としてはグローバル変数の削減が挙げられる。

Functions and Closures

Use func to declare a function. Call a function by following its name with a list of arguments in parentheses. 
Use -> to separate the parameter names and types from the function’s return type.

funcを使用して関数を宣言します。 カッコで囲まれた引数のリストを名前の後に付けて、関数を呼び出します。
 - >を使用して、関数の戻り値の型からパラメーター名と型を分離します。
func greet(person: String, day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet(person: "Bob", day: "Tuesday")
print(greet(person: "Bob", day: "Tuesday"))

下記が実行結果となります

Hello Bob, today is Tuesday.
By default, functions use their parameter names as labels for their arguments.
 Write a custom argument label before the parameter name, or write _ to use no argument label.

デフォルトでは、関数は引数のラベルとしてパラメータ名を使用します。 
パラメータ名の前にカスタム引数ラベルを記述するか、_を書いて引数ラベルを使用しないでください。
func greet(_ person: String, on day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
print(greet("John", on: "Wednesday"))

下記が実行結果となります

Linking ./.build/x86_64-unknown-linux/debug/TempCode
Hello John, today is Wednesday.
Use a tuple to make a compound value—for example, to return multiple values from a function. 
The elements of a tuple can be referred to either by name or by number.

タプルを使用して複合値を作成します(たとえば、関数から複数の値を返すなど)。 タプルの要素は、名前または番号のいずれかで参照できます。
タプルとはプログラミングにおいて複数の値を組にしたものである。プログラミング言語によって多少異なるが、大体以下のような性質を持つ。

組にする値の型はバラバラで構わない。(リストや配列は中の要素が全て同じ型であることを要求される)
中の値は順序がある。(なければ集合の方が概念としては近いかもしれない)
長さ(中に入っている値の数)は固定で変更できない。(リストは長さが可変)
イミュータブルである。(リストや配列は特に指定のない限り、中の各要素は変更可能な場合が多い)
動的型付けの言語では、リストと区別されず長さや要素が変更可能なこともある。

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.2)

下記が実行結果となります

Linking ./.build/x86_64-unknown-linux/debug/TempCode
120
120
Functions can be nested. Nested functions have access to variables that were declared in the outer function. 
You can use nested functions to organize the code in a function that is long or complex.

関数はネストできます。 
ネストされた関数は、外部関数で宣言された変数にアクセスできます。 
ネストされた関数を使用して、コードが長く複雑な関数で整理できます。
ネストとは、構造化プログラミングにおいてプログラムを構築する手法の一つで、あるルーチンやデータブロックの中に、別のルーチンやデータブロックがはめ込まれることである。入れ子構造とも呼ぶ。ループ文の中のループやルーチン内でにサブルーチンコール、関数呼び出しの引数に関数呼び出しを使うこと、コメントを含む文全体のコメント化など、多くの種類がある。
func returnFifteen() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()
    return y
}
returnFifteen()

下記が実行結果となります

Linking ./.build/x86_64-unknown-linux/debug/TempCode
15
Functions are a first-class type. This means that a function can return another function as its value.

関数はファーストクラスの型です。 これは、関数が別の関数をその値として返すことができることを意味します。
func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)

下記が実行結果となります

Linking ./.build/x86_64-unknown-linux/debug/TempCode
8
A function can take another function as one of its arguments.

関数は引数の1つとして別の関数をとることができます。
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)

下記が実行結果となります

Linking ./.build/x86_64-unknown-linux/debug/TempCode
7
Functions are actually a special case of closures: blocks of code that can be called later. 
The code in a closure has access to things like variables and functions that were available in the scope where the closure was created, even if the closure is in a different scope when it is executed—you saw an example of this already with nested functions. 
You can write a closure without a name by surrounding code with braces ({}). 
Use in to separate the arguments and return type from the body.

関数は実際にはクロージャの特殊なケースです。後で呼び出すことができるコードのブロックです。
クロージャー内のコードは、クロージャーが作成されたスコープで使用可能な変数や関数のようなものにアクセスできます
(実行時にクロージャーが異なるスコープにあっても)。
囲むコードを中括弧({})で囲んで名前なしのクロージャーを書くことができます。
inを使用して、引数と戻り値の型を本文から切り離します。
numbers.map({ (number: Int) -> Int in
    let result = 3 * number
    return result
})

下記が実行結果となります

Linking ./.build/x86_64-unknown-linux/debug/TempCode
60
57
21
36
You have several options for writing closures more concisely. 
When a closure’s type is already known, such as the callback for a delegate, you can omit the type of its parameters, its return type, or both. 
Single statement closures implicitly return the value of their only statement.

クロージャをより簡潔に書くためのいくつかのオプションがあります。 
デリゲートのコールバックなど、クロージャの型がすでにわかっている場合は、そのパラメータの型、戻り型、またはその両方を省略できます。 
単一の文の終了は、唯一の文の値を暗黙的に返します。
let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)

下記が実行結果となります

Linking ./.build/x86_64-unknown-linux/debug/TempCode
[60, 57, 21, 36]
You can refer to parameters by number instead of by name—this approach is especially useful in very short closures. 
A closure passed as the last argument to a function can appear immediately after the parentheses.
 When a closure is the only argument to a function, you can omit the parentheses entirely.

名前ではなく番号でパラメータを参照することができます。
このアプローチは、非常に短いクロージャでは特に便利です。
 関数への最後の引数として渡されたクロージャは、かっこの直後に現れます。 
クロージャが関数の唯一の引数であるときは、かっこを完全に省略することができます。
let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)

下記が実行結果となります

[20, 19, 12, 7]

長くなりましたが続きは次回やります