Swift The Programming Language Functionsまとめ


# Functions
+ 関数は、特定のタスクを実行する独立したコードブロック
+ Swiftのすべての関数には型があり、関数のパラメータの型と戻り値の型で構成されます。
+ この型はSwiftの他の型と同様に使うことができるので、以下のことができる
    + 他の関数にパラメータとして関数を渡すこと
    + 関数から関数を返すこと
+ 関数のスコープ内で別の関数を記述することもできる

# Defining and Calling Functions
## Define Functions
+ 全ての関数は関数名を持ち、関数が実行するタスクを表現する
+ パラメータ： 任意。入力値として取る1つ以上の名前と型を持つパラメータを定義できる
+ 返り値: 任意。出力値として返す値の型を定義できる

## Call Functions
+ 名前と関数のパラメータの型に一致する入力値（引数）を渡すことで関数が呼ばれる
+ 関数の引数は、関数のパラメータリストと同じ順序にする必要がある

```
func sayHelloAgain(personName: String) -> String {
    return "Hello again, " + personName + "!"
}

print(sayHelloAgain("Anna"))
// "Hello again, Anna!" と出力
```

# Function Parameters and Return Values
## Functions Without Parameters
+ パラメータを 1 つも取らない場合でも、関数名の後に丸括弧が必要
+ 関数を呼び出すときにも、関数名の後に丸括弧のペアが必要
 
```
func sayHelloWorld() -> String {
    return "hello, world"
}
print(sayHelloWorld())
// "hello, world" と出力
```

## Functions With Multiple Parameters
+ 関数の丸括弧の中に、カンマ区切りで複数の入力パラメータを記述できる
+ 引数が異なれば、関数名が同じでも異なる関数とみなす
+ 呼ぶときは、一つ目のパラメータにはラベルは不要
 
```
func sayHello(personName: String, alreadyGreeted: Bool) -> String {
    if alreadyGreeted {
        return sayHelloAgain(personName)
    } else {
        return sayHello(personName)
    }
}
print(sayHello("Tim", alreadyGreeted: true))
// "Hello again, Tim!" と出力
```
## Functions Without Return Values
+ 戻り値の型が定義されていない関数は、`Void`typeの特別な値を返します。
+ これは単に空のタプルで、() と記述できる

```
func sayGoodbye(personName: String) {
    print("Goodbye, \(personName)!")
}
sayGoodbye("Dave")
// "Goodbye, Dave!" と出力
```

## Functions with Multiple Return Values
+ 複数の値で構成される戻り値を返すための型として、tuple typeを使用する
+ タプルが関数から返される時にtupleのメンバーに名前を付ける必要はない

```
func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

let bounds = minMax([8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// "min is -6 and max is 109" と出力
```
## Optional Tuple Return Types
+ 返り値のtuple全体の値が`nil`になり得ることを反映したい時にoptional tupleを使う
+ `(Int, Int)?`や`(String, Int, Bool)?`とか
+ `(Int,Int)?`と`(Int?, Int?)`は異なる

```
func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}
```

# Function Parameter Names
+ 関数のパラメータには、外部パラメータ名とローカルパラメータ名がある
+ 外部パラメータ名は、関数呼び出し時の引数に使う
+ ローカルパラメータ名は、関数の実装で使う
 
## Specifying External Parameter Names
+ ローカルパラメータ名の前をスペースで区切って外部パラメータ名を記述する
+ 複数パラメータに外部パラメータ名を指定することで、呼び出すときにラベルを付ける必要がある
+ 関数の本体を読みやすく、意図を明確に維持したまま、表現力のある文章のように関数を呼び出せる

```
func sayHello(to person: String, and anotherPerson: String) -> String {
    return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello(to: "Bill", and: "Ted"))
// "Hello Bill and Ted!" と出力
```
## Omitting External Parameter Names
+ 関数の2つ目以降のパラメータに外部名を使用したくない場合には、明確な外部名ではなく`_`をパラメータに記述する
+ 1 つ目のパラメータは、デフォルトで外部パラメータ名を省略する
 
```
func someFunction(firstParameterName: Int, _ secondParameterName: Int) {
    // 1 つ目と 2 つ目のパラメータの引数値を
    // firstParameterName と secondParameterName で参照
}
someFunction(1, 2)
```

## Default Parameter Values
+ パラメータの型の後に続けて値を代入することで、関数のどのパラメータにでもデフォルト値を定義できる
+ 関数を呼び出すときにそのパラメータを省略するとdefault valueで関数が実行される
+ 省略しないで引数を指定すると、その引数を元に関数を実行する

## Variadic Parameters
+ 可変長（可変個）パラメータは、指定された型の値を 0 個以上受け取る
+ パラメータの型名の後にピリオドを 3 文字 (...) 挿入して可変長パラメータを記述する

```
func arithmeticMean(numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// 5 つの数値の算術平均である 3.0 を返す
arithmeticMean(3, 8.25, 18.75)
// 3 つの数値の算術平均である 10.0 を返す
```

## In-Out Parameters
+ 関数のパラメータの値を変更したい、かつ関数が終了した後もその変更を存続させたい場合に、そのパラメータを入出力パラメータとして定義する
+ パラメータのはじめに`inout`キーワードを置く
+ 入出力パラメータは関数に渡される値で、関数によって変更され、もとの値を置き換えるために関数の外に戻される
+ 入出力パラメータは、関数本体のスコープの外に影響がある
+ 引数として変数のみ渡せる
+ 入出力パラメータに引数として渡すとき、関数によって変更されることを示すアンパサンド (&) を変数名の前に置く

```
func swapTwoInts(inout a: Int, inout _ b: Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// "someInt is now 107, and anotherInt is now 3" と出力
```

# Function Types
+ すべての関数には、関数のパラメータの型と戻り値の型で構成される特定の関数型がある
+ `func addTwoInts(a: Int, _ b: Int) -> Int`の関数のtypeは`(Int, Int) -> Int`である
+ `func printHelloWorld()`の関数のtypeは`() -> Void `である

## Using Function Types
+ 関数型の定数または変数を定義し、適切な関数をその変数に代入することができる

```
var mathFunction: (Int, Int) -> Int = addTwoInts
let anotherMathFunction = addTwoInts
// anotherMathFunction は (Int, Int) -> Int 型と推論可能
```

## Function Types as Parameter Types
+ 別の関数のパラメータの型として関数型を使用できる

```
func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// "Result: 8" と出力
```

## Function Types as Return Types
+ 別の関数の戻り値の型として、関数型を使用できる
+ 関数が返す型として、`->`に続けて完全な関数型を記述します。

```
func stepForward(input: Int) -> Int {
    return input + 1
}
func stepBackward(input: Int) -> Int {
    return input - 1
}

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    return backwards ? stepBackward : stepForward
}
```

# Nested Functions
```
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backwards ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero はネストされた関数 stepForward() を参照
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!
```