素早いクロージャ


クロージャは、コード内で使用したり、値をパラメータとして渡すために使用できる機能コードの自己完結型ブロックです。

Swift のクロージャは、C および Objective-C のブロック、および他のプログラミング言語の匿名関数に似ています。

グローバル関数とネストされた関数は、実際には特別なクロージャです。

クロージャの形式は次のとおりです:

グローバル関数 ネストされた関数 クロージャ式
には名前がありますが、値を取得できません。 名前を使用すると、閉じた関数内の値をキャプチャすることもできます。 名前のないクロージャは軽量構文を使用し、コンテキストに基づいて値をキャプチャできます。

Swift のクロージャには多くの最適化があります:

  1. コンテキストに基づいてパラメータと戻り値の型を推測します

  2. 単一行の式クロージャから暗黙的に戻ります (つまり、クロージャ本体には 1 行のコードしかなく、 return省略)

  3. $0、$1などの簡略化されたパラメータ名を使用できます(0から始まり、i番目のパラメータを示します...)

  4. はトレーリングクロージャ構文(トレーリングクロージャ構文)を提供します

  5. 構文

    以下は、パラメータを受け取り、指定された型を返すクロージャ構文を定義します:

    {(parameters) -> return type in
       statements
    }

    import Cocoa
    
    let studname = { print("Swift 闭包实例。") }
    studname()

    上記のプログラム実行出力は次のとおりです:

    Swift 闭包实例。

    次のクロージャ形式は 2 つのパラメータを受け取り、ブール値を返します:

    {(Int, Int) -> Bool in
       Statement1
       Statement 2
        ---
       Statement n
    }

    import Cocoa
    
    let divide = {(val1: Int, val2: Int) -> Int in 
       return val1 / val2 
    }
    let result = divide(200, 20)
    print (result)

    上記プログラムの実行出力は次のとおりです:

    10

    クロージャ式

    クロージャ式は、簡潔な構文を使用してインラインクロージャを構築する方法です。 クロージャ式は、クロージャの作成を単純かつ簡単にするいくつかの構文の最適化を提供します。


    sort関数

    Swiftの標準ライブラリはsortと呼ばれる関数を提供します。これは、ソートのために指定したクロージャー関数に従って、既知の型の配列内の値をソートします。

    並べ替えが完了すると、sort(_:) メソッドは、元の配列と同じサイズで、同じタイプの要素を含み、要素が正しく並べ替えられた新しい配列を返します。元の配列は返されません。 sort(_:) メソッドで変更できます。

    sort(_:) メソッドは 2 つのパラメーターを渡す必要があります:

    • 既知の型の配列

    • クロージャー関数。配列と同じ型の 2 つの値を渡す必要があります。要素、および並べ替えが完了したときに、渡された最初のパラメーターが 2 番目のパラメーターの前にランク付けされるか、後にランク付けされるかを示すブール値を返します。最初のパラメーター値が 2 番目のパラメーター値の前に出現する場合、ソート クロージャー関数は true,反之返回false を返す必要があります。

    import Cocoa
    
    let names = ["AT", "AE", "D", "S", "BE"]
    
    // 使用普通函数(或内嵌函数)提供排序功能,闭包函数类型需为(String, String) -> Bool。
    func backwards(s1: String, s2: String) -> Bool {
        return s1 > s2
    }
    var reversed = names.sort(backwards)
    
    print(reversed)

    上記のプログラムの実行の出力結果は次のとおりです:

    ["S", "D", "BE", "AT", "AE"]

    最初の文字列 (s1) が 2 番目の文字列 (s2) より大きい場合、backwards 関数は true を返し、s1 が次のとおりであることを示します。新しい配列内にある s2 の前に表示されます。 文字列内の文字の場合、「より大きい」は「アルファベット順で後に出現する」ことを意味します。 これは、文字「B」が文字「A」より大きく、文字列「S」が文字列「D」より大きいことを意味します。 アルファベット順に逆順にソートされ、「AT」が「AE」より前にソートされます。


    パラメータ名の省略形

    Swift は、インライン関数のパラメータ名の省略形関数を自動的に提供します。 $0、$1、$2 を通じてクロージャのパラメータを順番に直接呼び出すことができます。

    import Cocoa
    
    let names = ["AT", "AE", "D", "S", "BE"]
    
    var reversed = names.sort( { 
    ["S", "D", "BE", "AT", "AE"]
     >  } ) print(reversed)

    $0 と $1 は、クロージャー内の最初と 2 番目の String 型パラメーターを表します。

    上記のプログラムの実行出力は次のとおりです:

    import Cocoa
    
    let names = ["AT", "AE", "D", "S", "BE"]
    
    var reversed = names.sort(>)
    print(reversed)

    クロージャ式でパラメータ名の省略形を使用する場合、クロージャ パラメータ リストでの定義を省略できます。パラメータ名の省略形に対応する型は、関数型の推論。 in キーワードは省略することもできます。


    演算子関数

    上記の例では、実際にはクロージャ式をより短い方法で記述することができます。

    Swift の String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool 型の値。 これは、sort(_:) メソッドの 2 番目のパラメーターで必要な関数の型と一致しています。 したがって、単に大なり記号を渡すだけで、Swift は大なり記号の文字列関数実装を使用することを自動的に推論できます。

    ["S", "D", "BE", "AT", "AE"]

    上記のプログラム実行の出力は次のとおりです:

    func someFunctionThatTakesAClosure(closure: () -> Void) {
        // 函数体部分
    }
    
    // 以下是不使用尾随闭包进行函数调用
    someFunctionThatTakesAClosure({
        // 闭包主体部分
    })
    
    // 以下是使用尾随闭包进行函数调用
    someFunctionThatTakesAClosure() {
      // 闭包主体部分
    }

    トレーリング クロージャ

    末尾のクロージャは関数の括弧の後に書かれたクロージャ式で、関数は最後のパラメータとしてそれを呼び出すことをサポートしています。

    import Cocoa
    
    let names = ["AT", "AE", "D", "S", "BE"]
    
    //尾随闭包
    var reversed = names.sort() { 
    ["S", "D", "BE", "AT", "AE"]
     >  } print(reversed)

    インスタンス

    reversed = names.sort { 
    func makeIncrementor(forIncrement amount: Int) -> () -> Int {
        var runningTotal = 0
        func incrementor() -> Int {
            runningTotal += amount
            return runningTotal
        }
        return incrementor
    }
     >  }

    sort() の後の { $0 > $1} は後続のクロージャです。

    上記のプログラムの実行の出力結果は次のとおりです:

    import Cocoa
    
    func makeIncrementor(forIncrement amount: Int) -> () -> Int {
        var runningTotal = 0
        func incrementor() -> Int {
            runningTotal += amount
            return runningTotal
        }
        return incrementor
    }
    
    let incrementByTen = makeIncrementor(forIncrement: 10)
    
    // 返回的值为10
    print(incrementByTen())
    
    // 返回的值为20
    print(incrementByTen())
    
    // 返回的值为30
    print(incrementByTen())

    注: 関数が 1 つのパラメータ (クロージャ式) のみを必要とする場合は、後続クロージャを使用するときに () を省略することもできます。 ()省略掉。

    10
    20
    30

    捕获值

    闭包可以在其定义的上下文中捕获常量或变量。

    即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。

    Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。

    嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。

    看这个例子:

    import Cocoa
    
    func makeIncrementor(forIncrement amount: Int) -> () -> Int {
        var runningTotal = 0
        func incrementor() -> Int {
            runningTotal += amount
            return runningTotal
        }
        return incrementor
    }
    
    let incrementByTen = makeIncrementor(forIncrement: 10)
    
    // 返回的值为10
    incrementByTen()
    
    // 返回的值为20
    incrementByTen()
    
    // 返回的值为30
    incrementByTen()
    
    // 返回的值为40
    incrementByTen()
    
    let alsoIncrementByTen = incrementByTen
    
    // 返回的值也为50
    print(alsoIncrementByTen())

    一个函数makeIncrementor ,它有一个Int型的参数amout, 并且它有一个外部参数名字forIncremet,意味着你调用的时候,必须使用这个外部名字。返回值是一个()-> Int

    50

    値のキャプチャ

    クロージャは、それが定義されているコンテキストで定数または変数をキャプチャできます。

    これらの定数と変数が定義されている元のドメインが存在しなくなった場合でも、クロージャはクロージャ関数本体でこれらの値を参照および変更できます。

    Swift におけるクロージャの最も単純な形式は、ネストされた関数です。これは、他の関数の関数本体内で定義される関数です。

    ネストされた関数は、定義された定数と変数だけでなく、外部関数のすべてのパラメーターをキャプチャできます。


    この例を見てください:

    rrreee

    関数 makeIncrementor には、Int 型パラメーター amout があり、外部パラメーター名 forIncremet があります。つまり、呼び出すときは、この外部名を使用する必要があります。戻り値は ()->Int の関数です。

    関数の質問では、変数runningTotalと関数インクリメンタが宣言されています。

    インクリメンタ関数はパラメータを取得しませんが、runningTotal 変数と amount 変数は関数本体でアクセスされます。これは、それを含む関数本体内にすでに存在する runningTotal 変数と amount 変数をキャプチャすることによってこれを行うためです。

    量変数は変更されないため、インクリメンタは実際に変数のコピーをキャプチャして保存し、そのコピーはインクリメンタとともに保存されます。

    したがって、この関数を呼び出すと、累積されます:

    rrreee

    上記のプログラム実行の出力結果は次のとおりです:
rrreee
🎜クロージャは参照型です🎜🎜上記の例では、incrementByTen は定数ですが、クロージャは参照型を指しますこれらの定数によって、キャプチャした変数の値を増やすことができます。 🎜🎜これは、関数とクロージャが参照型であるためです。 🎜🎜関数/クロージャを定数または変数に代入する場合、実際には定数/変数の値を対応する関数/クロージャへの参照に設定することになります。 上記の例では、incrementByTen が指すクロージャへの参照は定数であり、クロージャのコンテンツ自体ではありません。 🎜🎜これは、クロージャを 2 つの異なる定数/変数に割り当てると、両方の値が同じクロージャを指すことも意味します: 🎜rrreee🎜上記のプログラム実行の出力は次のとおりです: 🎜rrreee🎜🎜