Swift 言語ガイド – 6. 関数

swift

はじめに

公式ページのSwift 言語ガイド「The Swift Programming Language Swift 5.3」に基づき記載いたします。本ページでは、「関数」について記載いたします。
記載内容に誤り等ございましたら、ご連絡をいただければ幸いです。

6. 関数

関数は、特定のタスクを実行する自己完結型のコードチャンクです。関数にその機能を識別する名前を付けます。この名前は、関数を「呼び出し」て、必要に応じてタスクを実行するために使用されます。

Swiftの統合関数構文は、パラメータ名のない単純なCスタイルの関数から、各パラメータの名前と引数ラベルを持つ複雑なObjective-Cスタイルのメソッドまで、あらゆるものを表現するのに十分な柔軟性を備えています。パラメータは、関数呼び出しを単純化するためのデフォルト値を提供し、関数の実行が完了すると渡された変数を変更するin-outパラメータとして渡すことができます。

Swiftのすべての関数には、関数のパラメータ型と戻り値の型で構成される型があります。このタイプは、Swiftの他のタイプと同じように使用できます。これにより、関数をパラメータとして他の関数に渡したり、関数から関数を返したりすることが簡単になります。関数を他の関数内に記述して、ネストされた関数スコープ内に有用な機能をカプセル化することもできます。

6.1. 関数の定義と呼び出し

関数を定義するとき、オプションでパラメータと呼ばれる関数が入力として受け取る1つ以上の名前付き、型付き値を定義できます。オプションで関数が完了したときに出力として返す値の型(戻り値の型)を定義することもできます。

すべての関数には、関数が実行するタスクを説明する関数名があります。関数を使用するには、その関数をその名前で「呼び出し」、関数のパラメータの型に一致する入力値(引数と呼ばれる)を渡します。関数の引数は、常に関数のパラメータリストと同じ順序で指定する必要があります。

以下の例の関数は、greet(person:)と呼ばれます。これは、その機能であるためです。入力として人の名前を受け取り、その人の挨拶を返します。これを実現するには、1つの入力パラメータ(personという文字列値)と戻り値の型Stringを定義します。これには、その人への挨拶が含まれます。

func greet(person: String) -> String {
    let greeting = "Hello, " + person + "!"
    return greeting
}

この情報はすべて関数の定義にまとめられ、関数の定義の前にfuncキーワードが付けられます。関数の戻り値の型は、戻り値の矢印->(ハイフンの後に直角の括弧が続く)で示され、その後に返される型の名前が続きます。

定義は、関数が何をするか、何を受け取ることを期待するか、そしてそれが行われたときに何を返すかを記述します。この定義により、コードの他の場所から関数を明確に呼び出すことが容易になります。

print(greet(person: "Anna"))
// "Hello, Anna!"を出力します。
print(greet(person: "Brian"))
// "Hello, Brian!"を出力します。

greet(person:)関数を呼び出すには、greet(person: “Anna”)のように、person引数ラベルの後に文字列値を渡します。この関数は文字列値を返すため、上記のように、greet(person:)をprint(_:separator:terminator:)関数の呼び出しでラップして、その文字列を出力し、その戻り値を確認できます。

注意
print(_:separator:terminator:)関数には最初の引数のラベルがなく、他の引数にはデフォルト値があるためオプションです。関数構文のこれらのバリエーションについては、以下の関数の引数ラベルとパラメータ名およびデフォルトのパラメータ値で説明します。

greet(person:)関数の本体は、greetingと呼ばれる新しい文字列定数を定義し、それを単純な挨拶メッセージに設定することから始まります。このグリーティングは、returnキーワードを使用して関数から返されます。あいさつを返すというコード行で、関数は実行を終了し、あいさつの現在の値を返します。

異なる入力値を使用して、greet(person:)関数を複数回呼び出すことができます。上記の例は、「Anna」の入力値と「Brian」の入力値で呼び出された場合に何が起こるかを示しています。この関数は、それぞれの場合に合わせた挨拶を返します。

この関数の本体を短くするために、メッセージの作成とreturnステートメントを1行にまとめることができます。

func greetAgain(person: String) -> String {
    return "Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// "Hello again, Anna!"を出力します

6.2. 関数パラメータと戻り値

Swiftでは、関数パラメータと戻り値は非常に柔軟です。名前のない単一のパラメータを持つ単純な効用関数から、表現力豊かなパラメータ名とさまざまなパラメータオプションを持つ複雑な関数まで、あらゆるものを定義できます。

6.2.1. パラメータのない関数

入力パラメータを定義するための関数は必要ありません。入力パラメータのない関数は次のとおりです。この関数は、呼び出されるたびに常に同じ文字列メッセージを返します。

func sayHelloWorld() -> String {
    return "hello, world"
}
print(sayHelloWorld())
// "hello, world"を出力します

関数定義は、パラメータを取りませんが、関数名の後に括弧が必要です。関数が呼び出されると、関数名の後に空の括弧のペアも続きます。

6.2.2. 複数のパラメータを持つ関数

関数は、コンマで区切られた関数の括弧内に記述された複数の入力パラメータを持つことができます。

この関数は、人の名前と、その人がすでに入力として挨拶されているかどうかを受け取り、その人に適切な挨拶を返します。

func greet(person: String, alreadyGreeted: Bool) -> String {
    if alreadyGreeted {
        return greetAgain(person: person)
    } else {
      return greet(person: person)
    }
}
print(greet(person: "Tim", alreadyGreeted: true))
// "Hello again, Tim!"を出力します

greet(person:alreadyGreeted:)関数を呼び出すには、personというラベルの付いたString引数値と、コンマで区切って括弧で囲んだalreadyGreetedというラベルの付いたBool引数値の両方を渡します。この関数は、前のセクションで示したgreet(person:)関数とは異なることに注意してください。どちらの関数にもgreetで始まる名前がありますが、greet(person:alreadyGreeted:)関数は2つの引数を取りますが、greet(person:)関数は1つしか取りません。

6.2.3. 戻り値のない関数

戻り値の型を定義するために関数は必要ありません。greet(person:)関数のバージョンは次のとおりです。この関数は、独自の文字列値を返すのではなく出力します。

func greet(person: String) {
    print("Hello, \(person)!")
}
greet(person: "Dave")
// "Hello, Dave!"を出力します

値を返す必要がないため、関数の定義には戻り値の矢印(->)または戻り値の型は含まれていません。

注意
厳密に言えば、このバージョンのgreet(person:)関数は、戻り値が定義されていなくても、値を返します。戻り値の型が定義されていない関数は、Void型の特別な値を返します。これは単に空のタプルであり、()と記述されています。

関数の戻り値は、呼び出されたときに無視できます。

func printAndCount(string: String) -> Int {
    print(string)
    return string.count
}
func printWithoutCounting(string: String) {
    let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
// "hello、world"を出力し、値12を返します
printWithoutCounting(string: "hello, world")
// "hello、world"を出力しますが、値を返しません

最初の関数printAndCount(string:)は、文字列を出力してから、その文字数をIntとして返します。2番目の関数printWithoutCounting(string:)は、最初の関数を呼び出しますが、その戻り値を無視します。2番目の関数が呼び出されても、メッセージは最初の関数によって出力されますが、戻り値は使用されません。

注意
戻り値は無視できますが、値を返すことを示す関数は常にそうしなければなりません。戻り値の型が定義されている関数では、値を返さずに制御を関数の下部から外すことはできません。そうしようとすると、コンパイル時エラーが発生します。

6.2.4. 複数の戻り値を持つ関数

関数の戻り値の型としてタプル型を使用して、1つの複合戻り値の一部として複数の値を返すことができます。

以下の例では、minMax(array:)という関数を定義しています。この関数は、Int値の配列内の最小数と最大数を検索します。

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)
}

minMax(array:)関数は、2つのInt値を含むタプルを返します。これらの値にはminとmaxのラベルが付いているため、関数の戻り値をクエリするときに名前でアクセスできます。

minMax(array:)関数の本体は、currentMinおよびcurrentMaxと呼ばれる2つの作業変数を、配列の最初の整数の値に設定することから始まります。次に、関数は配列内の残りの値を反復処理し、各値をチェックして、それぞれcurrentMinおよびcurrentMaxの値よりも小さいか大きいかを確認します。最後に、全体の最小値と最大値が2つのInt値のタプルとして返されます。

タプルのメンバー値は関数の戻り値の型の一部として名前が付けられているため、ドット構文でアクセスして、見つかった最小値と最大値を取得できます。

let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// "min is -6 and max is 109"を出力します

タプルのメンバーは、関数の戻り値の型の一部としてすでに指定されているため、関数からタプルが返される時点で名前を付ける必要がないことに注意してください。

6.2.5. オプショナルのタプルの戻り値の型

関数から返されるタプルの型がタプル全体に対して「値なし」になる可能性がある場合は、オプショナルのタプルの戻り値の型を使用して、タプル全体がnilになる可能性があるという事実を反映できます。(Int, Int)?または(String, Int, Bool)?のように、タプル型の閉じ括弧の後に疑問符を配置して、オプショナルのタプルの戻り値の型を記述します。

注意
(Int, Int)?などのオプションのタプルタイプは、(Int?, Int?)などのオプショナルの型を含むタプルとは異なります。オプショナルのタプル型を使用すると、タプル内の個々の値だけでなく、タプル全体がオプショナルになります。

上記のminMax(array:)関数は、2つのInt値を含むタプルを返します。ただし、この関数は、渡された配列に対して安全性チェックを実行しません。配列引数に空の配列が含まれている場合、上記で定義したminMax(array:)関数は、array [0]にアクセスしようとしたときにランタイムエラーをトリガーします。

空の配列を安全に処理するには、オプショナルのタプルの戻り値の型を指定してminMax(array:)関数を記述し、配列が空の場合はnilの値を返します。

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)
}

オプショナルバインディングを使用して、このバージョンのminMax(array:)関数が実際のタプル値を返すかnilを返すかを確認できます。

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
print(“min is (bounds.min) and max is (bounds.max)”)
}
// 「最小は-6、最大は109」を出力します

6.2.6. 暗黙のリターンを伴う関数

関数の本体全体が単一の式である場合、関数は暗黙的にその式を返します。たとえば、以下の両方の関数の動作は同じです。

func greeting(for person: String) -> String {
    "Hello, " + person + "!"
}
print(greeting(for: "Dave"))
// "Hello, Dave!"を出力します

func anotherGreeting(for person: String) -> String {
    return "Hello, " + person + "!"
}
print(anotherGreeting(for: "Dave"))
// "Hello, Dave!"を出力します

Greeting(for:)関数の定義全体は、グリーティングメッセージでそのメッセージを返します。つまり、この短い形式を使用できます。anotherGreeting(for:)関数は、より長い関数のようにreturnキーワードを使用して、同じグリーティングメッセージを返します。1つのreturn行として記述した関数は、returnを省略できます。

Shorthand Getter Declarationでわかるように、プロパティゲッターは暗黙的な戻り値を使用することもできます。

注意
暗黙の戻り値として記述したコードは、何らかの値を返す必要があります。たとえば、fatalError(“Oh no!”)またはprint(13)を暗黙の戻り値として使用することはできません。

6.3. 関数の引数ラベルとパラメータ名

各関数パラメータには、引数ラベルとパラメータ名の両方があります。引数ラベルは、関数を呼び出すときに使用されます。各引数は、その前に引数ラベルを付けて関数呼び出しに書き込まれます。パラメータ名は、関数の実装で使用されます。デフォルトでは、パラメータはパラメータ名を引数ラベルとして使用します。

func someFunction(firstParameterName: Int, secondParameterName: Int) {
    // 関数本体では、firstParameterNameとsecondParameterNameは
    // 最初と2番目のパラメータの引数値を参照します
}
someFunction(firstParameterName: 1, secondParameterName: 2)

すべてのパラメータには一意の名前を付ける必要があります。複数のパラメータに同じ引数ラベルを付けることは可能ですが、一意の引数ラベルを使用すると、コードが読みやすくなります。

6.3.1. 引数ラベルの指定

パラメータ名の前に、スペースで区切って引数ラベルを記述します。

func someFunction(argumentLabel parameterName: Int) {
    // 関数本体では、parameterNameはそのパラメータの引数値を
    // 参照します。
}

これは、人の名前と出身地を受け取り、挨拶を返すgreet(person:)関数のバリエーションです。

func greet(person: String, from hometown: String) -> String {
    return "Hello \(person)!  Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// "Hello Bill!  Glad you could visit from Cupertino."を出力します

引数ラベルを使用すると、表現力のある文のような方法で関数を呼び出すことができますが、それでも、読み取り可能で意図が明確な関数本体を提供できます。

6.3.2. 引数ラベルの省略

パラメータの引数ラベルが必要ない場合は、そのパラメータの明示的な引数ラベルの代わりにアンダースコア(_)を記述します。

func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
    // 関数本体では、firstParameterNameとsecondParameterNameは、
    // 最初と2番目のパラメータの引数値を参照します
}
someFunction(1, secondParameterName: 2)

パラメータに引数ラベルがある場合、関数を呼び出すときに引数にラベルを付ける必要があります。

6.3.3. デフォルトのパラメータ値

パラメータの型の後に値をパラメータに割り当てることにより、関数内の任意のパラメータのデフォルト値を定義できます。デフォルト値が定義されている場合は、関数を呼び出すときにそのパラメータを省略できます。

func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
    // この関数を呼び出すときに2番目の引数を省略した場合、
    // parameterWithDefaultの値は関数本体内で12になります
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefaultは6です
someFunction(parameterWithoutDefault: 4) // parameterWithDefaultは12です

デフォルト値のないパラメータは、関数のパラメータリストの先頭で、デフォルト値のあるパラメータの前に配置します。通常、デフォルト値を持たないパラメータは、関数の意味にとってより重要です。最初にパラメータを書き込むと、デフォルトパラメータが省略されているかどうかに関係なく、同じ関数が呼び出されていることを簡単に認識できます。

6.3.4. 可変個引数パラメータ

可変個引数パラメータは、指定された型の0個以上の値を受け入れます。可変個引数パラメータを使用して、関数が呼び出されたときにパラメータにさまざまな数の入力値を渡すことができるように指定します。パラメータの型名の後に3つのピリオド文字(…)を挿入して、可変個引数パラメータを記述します。

可変個引数パラメータに渡された値は、適切な型の配列として関数の本体内で使用できるようになります。たとえば、数値の名前とDouble…の型を持つ可変個引数パラメータは、[Double]型の数値と呼ばれる定数配列として関数の本体内で使用可能になります。

以下の例では、任意の長さの数値のリストの算術平均(平均とも呼ばれます)を計算します。

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を返します

注意
関数には、最大で1つの可変個引数パラメータを含めることができます。

6.3.5. In-Outパラメータ

関数パラメータはデフォルトで定数です。関数の本体内から関数パラメータの値を変更しようとすると、コンパイル時エラーが発生します。これは、パラメータの値を誤って変更できないことを意味します。関数でパラメータの値を変更する必要があり、関数呼び出しが終了した後もそれらの変更を保持する場合は、代わりにそのパラメータをin-outパラメータとして定義します。

パラメータのタイプの直前にinoutキーワードを配置することにより、in-outパラメータには、関数に渡され、関数によって変更され、関数から戻されて元の値を置き換える値があります。in-outパラメータの動作および関連するコンパイラーの最適化の詳細については、「In-Outパラメータ」を参照してください。

in-outパラメータの引数としてのみ変数を渡すことができます。定数とリテラルは変更できないため、引数として定数またはリテラル値を渡すことはできません。変数をin-outパラメータに引数として渡すときは、変数名の直前にアンパサンド(&)を配置して、関数で変更できることを示します。

注意
In-outパラメータにデフォルト値を設定したり、可変個引数パラメータをinoutとしてマークしたりすることはできません。

これは、swapTwoInts(_:_:)という関数の例です。この関数には、aとbという2つのin-outの整数パラメータがあります。

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

swapTwoInts(_:_:)関数は、単にbの値をaにスワップし、aの値をbにスワップします。この関数は、aの値をtemporaryAと呼ばれる一時定数に格納し、bの値をaに割り当ててから、temporaryAをbに割り当てることによってこのスワップを実行します。

Int型の2つの変数を指定してswapTwoInts(_:_:)関数を呼び出し、それらの値を交換できます。someIntおよびanotherIntの名前は、swapTwoInts(::)関数に渡されるときに、接頭辞としてアンパサンドが付けられることに注意してください。

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"を出力します

上記の例は、someIntとanotherIntの元の値が、元々関数の外部で定義されていたとしても、swapTwoInts(_:_:)関数によって変更されることを示しています。

注意
入出力パラメータは、関数から値を返すことと同じではありません。上記のswapTwoIntsの例では、戻り値の型を定義したり値を返したりすることはありませんが、someIntとanotherIntの値を変更します。In-Outパラメータは、関数がその関数本体の範囲外で効果を持つための代替方法です。

6.4. 関数型

すべての関数には特定の関数型があり、パラメータ型と関数の戻り値の型で構成されています。

例えば:

func addTwoInts(_ a: Int, _ b: Int) -> Int {
    return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
    return a * b
}

この例では、addTwoIntsおよびmultiplyTwoIntsと呼ばれる2つの単純な数学関数を定義します。これらの関数はそれぞれ2つのInt値を取り、適切な数学演算を実行した結果であるInt値を返します。

これらの関数の両方の型は、(Int, Int) -> Intです。 これは次のように読むことができます:

「両方ともInt型の2つのパラメータを持ち、Int型の値を返す関数。」

パラメータや戻り値のない関数の別の例を次に示します。

func printHelloWorld() {
    print("hello, world")
}

この関数の型は、() -> Void、または「パラメータを持たず、Voidを返す関数」です。

6.4.1. 関数型の使用

Swiftの他の型と同じように関数型を使用します。たとえば、定数または変数を関数型として定義し、その変数に適切な関数を割り当てることができます。

var mathFunction:(Int、Int) -> Int = addTwoInts

これは次のように読むことができます:

「「2つのInt値を取り、Int値を返す関数」の型を持つmathFunctionという変数を定義します。この新しい変数を、addTwoIntsという関数を参照するように設定します。」

addTwoInts(_:_:)関数はmathFunction変数と同じ型であるため、この割り当てはSwiftの型チェッカーによって許可されます。

これで、割り当てられた関数をmathFunctionという名前で呼び出すことができます。

print("Result: \(mathFunction(2, 3))")
// "Result: 5"を出力します

非関数型の場合と同じ方法で、同じ一致型の異なる関数を同じ変数に割り当てることができます。

mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// "Result: 6"を出力します

他の型と同様に、関数を定数または変数に割り当てるときに、Swiftに任せて、関数型を推測することができます。

let anotherMathFunction = addTwoInts
// anotherMathFunctionは、型(Int, Int) -> Intであると推測されます

6.4.2. パラメータ型としての関数型

(Int, Int) -> Intなどの関数型を別の関数のパラメータ型として使用できます。これにより、関数の実装のいくつかの側面を、関数が呼び出されたときに関数の呼び出し元が提供できるようにすることができます。

上から数学関数の結果を出力する例を次に示します。

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

この例では、printMathResult(_:_:_:)という関数を定義します。この関数には、3つのパラメータがあります。最初のパラメータはmathFunctionと呼ばれ、型(Int, Int) -> Intです。この最初のパラメータの引数として、その型の任意の関数を渡すことができます。2番目と3番目のパラメータはaとbと呼ばれ、どちらもInt型です。これらは、提供されている数学関数の2つの入力値として使用されます。

printMathResult(_:_:_:)が呼び出されると、addTwoInts(_:_:)関数、および整数値3と5が渡されます。提供された関数を値3と5で呼び出し、8の結果を出力します。

printMathResult(_:_:_:)の役割は、適切な型の数学関数を呼び出し結果を出力することです。その関数の実装が実際に何をするかは重要ではありません。関数が正しい型であることが重要です。これにより、printMathResult(_:_:_:)は、その機能の一部を関数の呼び出し元に型セーフな方法で渡すことができます。

6.4.3. 戻り値の型としての関数型

関数型を別の関数の戻り値の型として使用できます。これを行うには、戻り関数の戻り矢印(->)の直後に完全な関数型を記述します。

次の例では、stepForward(_:)とstepBackward(_:)という2つの単純な関数を定義しています。stepForward(_:)関数は、入力値より1大きい値を返し、stepBackward(_:)関数は、入力値より1小さい値を返します。両方の関数のタイプは(Int) -> Int:です。

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

これがchooseStepFunction(backward:)という関数で、戻り値の型は(Int) -> Intです。ChooseStepFunction(backward:)関数は、backward:と呼ばれるブールパラメータに基づいてstepForward(_:)関数またはstepBackward(_:)関数を返します。

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

これで、chooseStepFunction(backward:)を使用して、一方向または他の方向にステップする関数を取得できます。

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZeroがstepBackward()関数を参照するようになりました

上記の例では、currentValueという変数を徐々にゼロに近づけるために正または負のステップが必要かどうかを判断します。currentValueの初期値は3です。これは、currentValue > 0がtrueを返し、chooseStepFunction(backward:)がstepBackward(_:)関数を返すことを意味します。返された関数への参照は、moveNearerToZeroという定数に格納されます。

moveNearerToZeroが正しい関数を参照するようになったので、これを使用してゼロまでカウントできます。

print("Counting to zero:")
// ゼロまで数える:
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!

6.5. 入れ子関数

この章でこれまでに遭遇したすべての関数は、グローバルスコープで定義されたグローバル関数の例です。ネストされた関数と呼ばれる、他の関数の本体内に関数を定義することもできます。

ネストされた関数は、デフォルトでは外部から隠されていますが、それを囲む関数によって呼び出して使用することができます。囲んでいる関数は、ネストされた関数の1つを返して、ネストされた関数を別のスコープで使用できるようにすることもできます。

上記のchooseStepFunction(backward:)の例を書き直して、ネストされた関数を使用して返すことができます。

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!
タイトルとURLをコピーしました