関数の定義と呼び出し
func greet(person: String) -> String { let greeting = "Hello, " + person + "!" return greeting }
関数パラメーターと戻り値
// パラメータなしの関数 func sayHelloWorld() -> String { return "hello, world" } // 複数のパラメーターを持つ関数 func greet(person: String, alreadyGreeted: Bool) -> String { if alreadyGreeted { return greetAgain(person: person) } else { return greet(person: person) } } // 戻り値のない関数 func greet(person: String) { print("Hello, \(person)!") }
注意
厳密に言えば、戻り値が定義されていなくても、関数は値を返します。戻り値の型が定義されていない関数は、typeの特別な値 void を返します。これは単に空のタプル()です。
複数の戻り値を持つ関数
関数の戻り値の型としてタプル型を使用して、複数の値を返すことができます。
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(array: [8, -6, 2, 109, 3, 71]) print("min is \(bounds.min) and max is \(bounds.max)")
オプショナルタプルの戻り値
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) }
注意
タプル全体がオプショナルの(Int, Int)?
と、個々のオプショナルの(Int?, Int?)
とは意味が異なる。
暗黙的な戻り値を持つ関数
関数の本体全体が単一の式である場合、関数は暗黙的にその式を返します。たとえば、以下の両方の関数は同じ動作をします。
func greeting(for person: String) -> String { // return がない、暗黙的な戻り値 "Hello, " + person + "!" } print(greeting(for: "Dave")) func anotherGreeting(for person: String) -> String { return "Hello, " + person + "!" } print(anotherGreeting(for: "Dave"))
関数の引数ラベルとパラメーター名
各関数パラメーターには、引数ラベルとパラメーター名の両方があります。
// 関数の実装で使用されるとき、パラメータ名 func someFunction(firstParameterName: Int, secondParameterName: Int) { } // 関数を呼び出すとき、引数ラベル someFunction(firstParameterName: 1, secondParameterName: 2) // 引数ラベルを使用すると、読みやすく意図が明確な関数本体を提供しながら、表現力豊かな文のように関数を呼び出すことができます。 // 引数ラベルの省略 // パラメータの引数ラベルが不要_な場合は、そのパラメータの明示的な引数ラベルの代わりにアンダースコア()を記述します。 func someFunction(_ firstParameterName: Int, secondParameterName: Int) { } someFunction(1, secondParameterName: 2) // パラメータに引数ラベルがある場合、関数を呼び出すときに引数にラベルを付ける必要があります。 // デフォルトのパラメータ値 // パラメータのタイプの後にパラメータに値を割り当てることにより、関数内の任意のパラメータのデフォルト値を定義できます。デフォルト値が定義されている場合は、関数を呼び出すときにそのパラメーターを省略できます。 func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) { } someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) someFunction(parameterWithoutDefault: 4) // parameterWithDefault is 12 // デフォルト値を持たないパラメーターを最初に配置します。通常、デフォルト値を持たないパラメータは、デフォルト値を持たないパラメーターより重要です。 // 可変パラメータ // ...により、可変パラメーターを記述します。 // 関数には、可変引数は1つしか含めることができません。 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) // returns 3.0, which is the arithmetic mean of these five numbers arithmeticMean(3, 8.25, 18.75) // returns 10.0, which is the arithmetic mean of these three numbers // 入出力パラメーター // 関数パラメーターは、デフォルトでは定数です。関数の本体内から関数パラメーターの値を変更しようとすると、コンパイル時エラーが発生します。つまり、誤ってパラメーターの値を変更することはできません。 // パラメータのタイプの直前に inout キーワードを配置することで、入出力パラメータを記述します。入出力パラメーターは、関数によって値が変更され、関数から戻されます。 func swapTwoInts(_ a: inout Int, _ b: inout 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)") // Prints "someInt is now 107, and anotherInt is now 3" // inout 入出力パラメータにデフォルト値を設定することはできません。 // swapTwoInts(_:_:)関数は、単にaとbの値をスワップします。 "_" により、関数呼び出し時の引数ラベルが省略可能であることを示しています。 func swapTwoInts(_ a: inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA } // var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt, &anotherInt)
関数のタイプ
すべての関数には、パラメーターの型と関数の戻りの型で構成される特定の関数型があります。
例えば:
func addTwoInts(_ a: Int, _ b: Int) -> Int { return a + b } func multiplyTwoInts(_ a: Int, _ b: Int) -> Int { return a * b } // この関数のタイプは (Int, Int) -> Int です。 func printHelloWorld() { print("hello, world") } // この関数のタイプは、() -> Void です。
関数タイプの使用
関数型は、Swiftの他の型と同じように使用します。たとえば、定数または変数を関数タイプとして定義し、適切な関数をその変数に割り当てることができます。
var mathFunction: (Int, Int) -> Int = addTwoInts // 割り当てられた関数を次の名前で呼び出すことができます print("Result: \(mathFunction(2, 3))") // Prints "Result: 5" // 一致する型が同じである別の関数を、同じ変数に割り当てることができます。 mathFunction = multiplyTwoInts print("Result: \(mathFunction(2, 3))") // Prints "Result: 6"
パラメータ型としての関数型
(Int, Int) -> Int などの関数型を、別の関数のパラメーターとして使用できます。
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) { print("Result: \(mathFunction(a, b))") } printMathResult(addTwoInts, 3, 5) // Prints "Result: 8"
戻り型としての関数型
関数の型を別の関数の戻り値の型として使用できます。これを行うに->
は、戻り関数の戻り矢印の直後に完全な関数タイプを記述します。
func stepForward(_ input: Int) -> Int { return input + 1 } func stepBackward(_ input: Int) -> Int { return input - 1 } func chooseStepFunction(backward: Bool) -> (Int) -> Int { return backward ? stepBackward : stepForward } var currentValue = 3 let moveNearerToZero = chooseStepFunction(backward: currentValue > 0) print("Counting to zero:") // Counting to zero: while currentValue != 0 { print("\(currentValue)... ") currentValue = moveNearerToZero(currentValue) } print("zero!") // 3... // 2... // 1... // zero!
ネストされた関数
この章でこれまでに出てきたすべての関数は、グローバルスコープで定義されたグローバル関数の例です。ネストされた関数と呼ばれる他の関数の本体内に関数を定義することもできます。
ネストされた関数は、デフォルトでは外部から隠されていますが、それを囲んでいる関数から呼び出して使用することができます。囲んでいる関数は、ネストされた関数の1つを返すことにより、ネストされた関数を別のスコープで使用することもできます。
func chooseStepFunction(backward: Bool) -> (Int) -> Int { func stepForward(input: Int) -> Int { return input + 1 } func stepBackward(input: Int) -> Int { return input - 1 } return backward ? stepBackward : stepForward } var currentValue = -4 let moveNearerToZero = chooseStepFunction(backward: currentValue > 0) // moveNearerToZero now refers to the nested stepForward() function while currentValue != 0 { print("\(currentValue)... ") currentValue = moveNearerToZero(currentValue) } print("zero!") // -4... // -3... // -2... // -1... // zero!