Swiftのクロージャーを最大限に使用します

Objective-C 2.0にはクロージャーブロックと呼ばれる)が含まれているという事実にもかかわらず、Apple APIは以前はしぶしぶ使用していました。 おそらくこれが、ブロックがどこでも使用されるAFNetworkingのようなサードパーティのライブラリを使用することを多くのiOSプログラマが楽しんだ理由の一部であると思われます。 Swiftのリリース、およびAPIへの新しい機能の追加により、クロージャーの操作は非常に便利になりました。 Swiftでの構文の機能と、それらを使用して「実行」できるトリックを見てみましょう。







単純なものから複雑なもの、退屈なものから楽しいものへと移行します。 「関数」、「パラメータ」、「ダブル」のマントラを多用していることをおaびしますが、歌から言葉を消すことはできません。



パート1.入門



1.1。 ファーストクラスオブジェクト



始めるために、Swiftの機能はファーストクラスオブジェクトの誇り高い地位のキャリアであるという考えで強化しましょう。 つまり、関数を変数に格納し、パラメーターとして渡して、別の関数の結果として返すことができます。 「機能のタイプ」の概念が導入されています。 この型は、戻り値の型だけでなく、入力引数の型も記述します。

加算と減算の2つの数学演算を記述する2つの類似した関数があるとします。

func add(op1: Double, op2: Double) -> Double { return op1 + op2 } func subtract(op1: Double, op2: Double) -> Double { return op1 - op2 }
      
      





それらのタイプは次のように説明されます。

 (Double, Double) -> Double
      
      





これは次のように読むことができます。「前は、 Double型の2つの入力パラメーターとDouble型の戻り値を持つ関数型です。」

このタイプの変数を作成できます:

 //   var operation: (Double, Double) -> Double //      //   ,    - : for i in 0..<2 { if i == 0 { operation = add } else { operation = subtract } let result = operation(1.0, 2.0) // ""  println(result) }
      
      





上記のコードはコンソールに出力されます:

3.0

-1.0



1.2。 短絡



最初のクラスオブジェクトのもう1つの特権を使用します。 前の例に戻ると、最後のパラメーターとして(Double、Double)-> Doubleのような古い関数の1つを取る新しい関数を作成できます。 これがどのように見えるかです:

 // (1) func performOperation(op1: Double, op2: Double, operation: (Double, Double) -> Double) -> Double { // (2) return operation(op1, op2) // (3) }
      
      





コンポーネントのわかりにくい構文を分析してみましょう。 performOperation関数は、3つのパラメーターを取ります。



本体では、 performOperationは単純にoperationパラメーターに格納された関数の結果を返し、最初の2つのパラメーターを渡します。

これまでのところ混乱しているように見えますが、はっきりしていません。 少し忍耐、紳士。



次に、変数ではなく、無名関数を3番目の引数として渡し、 {}括弧で囲みます。 この方法で渡されるパラメーターは、 クロージャーと呼ばます:

 let result = performOperation(1.0, 2.0, {(op1: Double, op2: Double) -> Double in return op1 + op2 // (5) }) // (4) println(result) //  3.0  
      
      





コードのスニペット(op1:Double、op2:Double)-> Double inは、いわば、クロージャーの「ヘッダー」です。 次のもので構成されます。



もう一度、ポイントごとに何が起こったかについて:

(1) 宣言されたperformOperation関数

(2)この関数は3つのパラメーターを取ります。 最初の2つはオペランドです。 後者は、これらのオペランドで実行される関数です。

(3) performOperationは、操作の結果を返します。

(4)クロージャーによって記述された関数は、 performOperationの最後のパラメーターとして渡されました。

(5)クロージャー本体は、オペランドに対して実行される操作を示します。



パート2.楽しい。

構文糖と予想外のパン



Swiftの作者は、言語ユーザーができるだけ少ないコードを記述し、プロジェクトのアーキテクチャに関するHabrの考えを読むことに貴重な時間を費やすことができるように、多くの努力をしました。 算術演算を使用した例に基づいて、どの状態まで「ねじり戻す」ことができるかがわかります。



2.1。 呼び出されたときに型を取り除きます。


第一に、コンパイラーが入力パラメーターのタイプをすでに知っているため、クロージャー内の入力パラメーターのタイプを明示的に指定することはできません。 関数呼び出しは次のようになります。

 performOperation(1.0, 2.0, {(op1, op2) -> Double in return op1 + op2 })
      
      





2.2。 テールクロージャ構文を使用します。


次に、クロージャーが関数の最後のパラメーターとして渡される場合、構文によりレコードを短縮でき、クロージャーコードは単に呼び出しの末尾に付加されます。

 performOperation(1.0, 2.0) {(op1, op2) -> Double in return op1 + op2 }
      
      





2.3。 キーワード「return」は使用しません。


この言語の素晴らしい(場合によっては)機能は、クロージャコードが1行に収まる場合、この行の結果が自動的に返されることです。 したがって、「return」キーワードは省略できます。

 performOperation(1.0, 2.0) {(op1, op2) -> Double in op1 + op2 }
      
      





2.4。 パラメーターには省略名を使用します。


どうぞ 興味深いことに、Swiftでは、クロージャーの入力パラメーターにいわゆる略記(英語の略記)名を使用できます。 つまり 各パラメータには、デフォルトで$ n形式のエイリアスが割り当てられます。nは、ゼロから始まるパラメータのシリアル番号です。 したがって、引数の名前を考え出す必要すらないことがわかります。 この場合、クロージャーの「ヘッダー」全体には意味的な負荷がかからなくなり、省略できます。

 performOperation(1.0, 2.0) { $0 + $1 }
      
      





同意します、この記録は最初にあったものと全く似ていません。



2.5。 ナイトムーブ:オペレーター機能。


これらはすべて花でした。 今ベリーがあります。

前のエントリーを見て、コンパイラーがクロージャーについて既に知っていることを考えてみましょう。 彼は、パラメーターの数( 2 )とそのタイプ( DoubleおよびDouble )を知っています。 戻り値のタイプを知っています( Double )。 クロージャーコードでは1行しか実行されないため、実行結果として返される必要があることを知っています。 このエントリを他の方法で単純化することは可能ですか?

それはあなたができることが判明しました。 クロージャーが2つの入力引数のみで機能する場合、これらの引数(オペランド)で実行されるクロージャーとして演算子関数を渡すことができます。 これで、呼び出しは次のようになります。

 performOperation(1.0, 2.0, +)
      
      





美人!

これで、最小限のコードを記述しながら、いくつかの条件に応じてオペランドに対して基本演算を実行できます。



ちなみに、Swiftでは、比較演算を演算子関数として使用することもできます。 次のようになります。

 func performComparisonOperation(op1: Double, op2: Double, operation: (Double, Double) -> Bool) -> Bool { return operation(op1, op2) } println(performComparisonOperation(1.0, 1.0, >=)) //  "true" println(performComparisonOperation(1.0, 1.0, <)) //  "false"
      
      





またはビット演算:

 func performBitwiseOperation(op1: Bool, op2: Bool, operation: (Bool, Bool) -> Bool) -> Bool { return operation(op1, op2) } println(performBitwiseOperation(true, true, ^)) //  "false" println(performBitwiseOperation(true, false, |)) //  "true"
      
      







Swiftは一種の楽しいプログラミング言語です。 この記事が、この言語に精通し始めている人や、iOSやMac OS Xの開発者がそこで何が起こっているのかに単に興味がある人に役立つことを願っています。

___________________________________________________________________

UPD。:実際のアプリケーション


一部のユーザーは、実例が不足していることに不満を表明しました。 昨日、短絡を使ってエレガントに解決できる問題に出会いました。



優先度キューを作成する必要がある場合は、バイナリヒープを使用できます。 ご存知のように、これはMinHeapまたはMaxHeapのいずれかです。 最小または最大要素がそれぞれツリーのルートにあるヒープ。 MaxHeapからの基本的なMinHeap実装は、要素の追加/削除後にバイナリヒープ不変式を復元するときの検証比較でのみ本質的に異なります。



したがって、タイプ(T、T)-> Boolの 比較プロパティを含む基本クラスBinaryHeapを作成できます。 そして、このクラスのコンストラクターは比較メソッドを取り、それをheapifyメソッドで使用します。 基本クラスのプロトタイプは次のようになります。

 class BinaryHeap<T: Comparable>: DebugPrintable { private var array: Array<T?> private var comparison: (T, T) -> Bool private var used: Int = 0 // -- // Internal Methods internal func removeTop() -> T? { //... } internal func getTop() -> T? { //... } // Public Methods: func addValue(value: T) { if used == self.array.count { self.grow() } self.array[used] = value heapifyToTop(used, comparison) //   ,     self.used++ } init(size newSize: Int, comparison newComparison: (T, T) -> Bool) { array = [T?](count: newSize, repeatedValue: nil) comparison = newComparison } }
      
      





さて、 MinHeapクラスMaxHeapクラスを作成するには、 BinaryHeapから継承するだけで十分です。コンストラクターでは、適用する比較を明示的に指定するだけです。 これがクラスの外観です。

 class MaxHeap<T: Comparable>: BinaryHeap<T> { func getMax() -> T? { return self.getTop() } func removeMax() -> T? { return self.removeTop() } init(size newSize: Int) { super.init(size: newSize, {$0 > $1}) } }
      
      





 class MinHeap<T: Comparable>: BinaryHeap<T> { func getMin() -> T? { return self.getTop() } func removeMin() -> T? { return self.removeTop() } init(size newSize: Int) { super.init(size: newSize, {$0 <= $1}) } }
      
      






All Articles