質問: なぜプログラムはクロージャーを使うのでしょうか? ここでクロージャーを説明する多くの投稿を読んだ後、私はまだ重要な概念が欠けています:なぜクロージャーを書くのですか?プログラマーはどのような特定のタスクを実行するでしょうか?閉鎖によって最もよく役立つ?swiftのクロージャの例は、nsurlへのアクセスとリバースジオコーダの使用です。 これはそのような例の1つです。 残念ながら、これらのコースはクロージャを提示するだけで、コードソリューションがクロージャとして記述されている理由を説明します。現実世界のプログラミング問題の例で、脳が「ああ、私はこれのクロージャーを書くべきだ」と言う可能性があり、理論的な議論よりも有益です。このサイトで利用できる理論的な議論に事欠きません。
回答: クロージャーはrun()メソッドを実装するオブジェクトと同等であり、逆にオブジェクトはクロージャーでエミュレートできます。 クロージャーの利点は、関数を期待するところならどこでも簡単に使用できることです:別名高次関数、単純なコールバック(または戦略パターン)。アドホッククロージャーを構築するためにインターフェース/クラスを定義する必要はありません。 オブジェクトの利点は、複数のメソッドや異なるインターフェイスなど、より複雑な相互作用が可能になることです。 したがって、クロージャーまたはオブジェクトの使用は、ほとんどの場合スタイルの問題です。クロージャによって簡単に作成できるものの、オブジェクトを使用して実装するのが不便な例を次に示します。 (let ((seen)) (defun register-name (name) (pushnew name seen :test #'string=)) (defun all-names () (copy-seq seen)) (defun reset-name-registry () (setf seen nil))) 基本的に、グローバルクロージャを介してのみアクセスされる非表示の状態をカプセル化します。オブジェクトを参照する必要はなく、3つの関数によって定義されたプロトコルのみを使用します。 答えをアドレスに拡張しています このコメント supercat *から。 一部の言語ではオブジェクトの存続期間を正確に制御できるという事実についてのsupercatの最初のコメントを信頼していますが、クロージャーについては同じことが当てはまりません。ただし、ガベージコレクションされた言語の場合、オブジェクトのライフタイムは一般に無制限であるため、呼び出されるべきではない動的なコンテキストで呼び出される可能性があるクロージャを構築することが可能です(ストリームの後にクロージャから読み取る)たとえば、閉じています)。ただし、クロージャの実行を保護する制御変数をキャプチャすることで、このような誤用を防ぐのは非常に簡単です。より正確には、これは私が(common lispで)念頭に置いているものです:(defun guarded (function) (let ((active t)) (values (lambda (&rest args) (when active (apply function args))) (lambda () (setf active nil))))) ここでは、関数指定子functionを取り、2つのクロージャーを返します。どちらもactiveというローカル変数をキャプチャします。 最初のものは、functionがtrueの場合にのみ、activeに委任します 2つ目は、actionをnilに設定します。別名、falseです。 (when active ...)の代わりに、当然のことながら(assert active)式を使用することもできます。これは、クロージャが呼び出されるべきでないときに呼び出された場合に例外をスローする可能性があります。また、安全でないコードは、使用方法を誤ると既に例外をスローする可能性があるため、このようなラッパーが必要になることはほとんどありません。以下にその使用方法を示します。(use-package :metabang-bind) ;; for bind (defun example (obj1 obj2) (bind (((:values f f-deactivator)(guarded (lambda () (do-stuff obj1)))) ((:values g g-deactivator)(guarded (lambda () (do-thing obj2))))) ;; ensure the closure are inactive when we exit (unwind-protect ;; pass closures to other functions (progn (do-work f) (do-work g)) ;; cleanup code: deactivate closures (funcall f-deactivator) (funcall g-deactivator)))) 非アクティブ化クロージャは他の関数にも与えることができることに注意してください。ここでは、ローカルのactive変数はfとgの間で共有されていません。また、activeに加えて、fはobj1のみを参照し、gはobj2のみを参照します。supercatによって言及されたもう1つの点は、クロージャーがメモリーリークを引き起こす可能性があることですが、残念ながら、ガベージコレクションされた環境のほとんどすべてに当てはまります。それらが利用可能な場合、これはweak pointersによって解決できます(クロージャ自体はメモリに保持される可能性がありますが、他のリソースのガベージコレクションを妨げません)。