swift学習-閉パッケージ

4655 ワード

  • 閉パケットは機能的自己包含モジュールであり、コードで伝達および使用することができる.Swiftの閉パッケージは、CおよびObjective-Cのblocksおよび他のプログラミング言語のlambdasと似ています.
  • 閉パケットは、そのコンテキスト内の任意の定数および変数の参照をキャプチャおよび格納することができる.これがいわゆる閉じてこれらの定数と変数を包んでいる、通称閉じている.Swiftは、取得中に関連するメモリ操作を管理します.
  • 関数の章で紹介されているグローバルおよびネストされた関数は、実際には特殊な閉パッケージであり、閉パッケージは次の3つの形式の1つを採用しています.
  • グローバル関数は、名前はあるが値は取得されない閉パケット
  • である.
  • ネストされた関数は、名前があり、その閉じた関数ドメイン内の値をキャプチャできる閉じたパケット
  • である.
  • 閉パケット式は、そのコンテキスト内の変数または定数値をキャプチャできる軽量レベルの構文を用いて書かれた名前のない閉パケット
  • である.

    クローズドパッケージ式
    閉パケット式は、簡潔な構文を用いてインライン閉パケットを構築する方法である.閉パッケージ式は、いくつかの構文最適化に使用され、閉パッケージの作成が簡単になります.次の閉パケット式の例は、sort関数の定義と構文最適化の方法を数回の反復を用いて示す.反復のたびに同じ機能をより簡潔に述べた.
    sort関数
    次の閉パッケージ式の例では、sort関数を使用してStringタイプの配列をアルファベット逆順序でソートします.以下は初期配列値です.
    let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
    

    ソート関数には2つのパラメータがあります.
  • 既知のタイプ値の配列.
  • は、同じタイプの配列の内容の2つのパラメータを使用して閉包され、最初の値をソート時に2番目の値の前または後ろに配置するかどうかを示すブール値を返します.最初の値が2番目の値になる前に、閉パケットはtrueを返す必要があります.そうしないとfalseを返します.
  •  func backwards(s1: String, s2: String) -> Bool {2. return s1 > s2.
    }
     var reversed = sort(names, backwards)5. 
    // reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
    

    クローズドパッケージ式の構文
    閉包式構文には、次のような一般的な形式があります.
    { (parameters) -> returnType in
     statements
    }
    

    次の例では、backwards関数に対応する閉パッケージ式バージョンのコードを示します.
     reversed = sort(names, { (s1: String, s2: String) -> Bool in
    return s1 > s2
    })
    

    コンテキストに基づいてタイプを推定
    ソートクローズは関数のパラメータとして入力されるため、Swiftはそのパラメータと戻り値のタイプを推定することができる.sortは、2番目のパラメータがタイプ(String,String)->Boolの関数であることを望んでいるので、実際にはString,String,Boolタイプは閉パケット式定義の一部として必要ありません.すべてのタイプが正確に推定できるため、戻り矢印(->)とパラメータの周囲の括弧を省略することもできます.
     reversed = sort(names, { s1, s2 in return s1 > s2 } )
    

    単行式閉パッケージはreturnを省略できます
    reversed = sort(names, { s1, s2 in s1 > s2 } )
    

    パラメータ名の略記
    閉パッケージ式でパラメータ名の略記を使用する場合は、閉パッケージパラメータリストで定義を省略し、対応するパラメータ名の略記のタイプは関数タイプで推定されます.inキーワードも同様に省略することができる.なぜなら、このとき閉包式は
    reversed = sort(names, { $0 > $1 } )
    //$0   $1              String      。
    

    演算子関数
    実際には、上記の例の閉パッケージ式を書く方法もあります.SwiftのStringタイプは、2つのStringタイプのパラメータを1つの関数として受け入れ、Boolタイプの値を返すように、番号(>)より大きい文字列実装を定義します.これはsort関数の2番目のパラメータに必要な関数タイプにぴったり合っています.したがって、大きい番号を簡単に渡すことができます.Swiftは、大きい番号を使用したい文字列関数を自動的に推定します.
    reversed = sort(names, >)
    

    Trailing閉パッケージ
    長い閉パケット式を最後のパラメータとして関数に渡す必要がある場合は、trailing閉パケットを使用して関数の可読性を向上させることができます.Trailingクローズド・パッケージは、関数カッコの外(後)に書かれたクローズド・パッケージ式で、関数は最後のパラメータとして呼び出すことをサポートします.
    func someFunctionThatTakesAClosure(closure: () -> ()) {
     //      
     }
     //        trailing         
     someFunctionThatTakesAClosure({
     //       
    })//       trailing         
    someFunctionThatTakesAClosure() {
     //       
     }
    

    キャプチャ(Capture)
    閉パッケージは、定義されたコンテキストで定数または変数を取得できます.これらの定数と変数を定義する元の役割ドメインが存在しなくても、閉パケットは閉パケット関数内でこれらの値を参照および変更できます.
    Swiftの最も簡単な閉包形式はネスト関数,すなわち他の関数体内で定義された関数である.ネストされた関数は、外部関数のすべてのパラメータと定義された定数と変数をキャプチャします.
    次の例は、incrementorネスト関数と呼ばれるmakeIncrementorという関数です.ネスト関数incrementorは、コンテキストから2つの値、runningTotalおよびamountを取得します.その後makeIncrementorはincrementorを閉パッケージとして返します.incrementorを呼び出すたびに、amountをインクリメンタルとしてrunningTotalの値が増加します.
    func makeIncrementor(forIncrement amount: Int) -> () -> Int {
     var runningTotal = 0
    func incrementor() -> Int {
    runningTotal += amount
    return runningTotal
    }
     return incrementor
    

    incrementor関数はパラメータを取得していませんが、runningTotalとamount変数に関数内でアクセスします.これは、それを含む関数内に既に存在するrunningTotalおよびamount変数をキャプチャすることによって実現されるためである.
    amount変数が変更されていないため、incrementorは実際に変数のコピーをキャプチャして格納し、そのコピーはincrementorとともに格納される.
    ただし、関数を呼び出すたびにrunningTotalの値が変更されるため、incrementorは、変数の初期値のみをコピーするのではなく、現在のrunningTotal変数の参照を取得します.リファレンスをキャプチャすると、makeIncrementorが終了しても消えないことが保証され、incrementor関数が次回実行されるとrunningTotalが増加し続けることが保証されます.
    次に、makeIncrementorを使用する例を示します.
    let incrementByTen = makeIncrementor(forIncrement: 10)
    

    この例では、呼び出しのたびに10が加算されるincrementor関数を指すincrementByTenという定数を定義します.この関数を複数回呼び出すと、次の結果が得られます.
    incrementByTen()
    //      10
     incrementByTen()
    //      205. incrementByTen()
    //      30
    

    別のincrementorを作成すると、独自の独立したrunningTotal変数への参照があります.次の例では、incrementBySevneは、incrementByTenで取得された変数と何の関係もない新しいrunningTotal変数を取得します.
    let incrementBySeven = makeIncrementor(forIncrement: 7)
     incrementBySeven()3. //      74. incrementByTen()
    //      40