回答
這是一個非常簡單的例子,但是我使用閉包來「部分應用」函數,如果我已經有1個參數,但是需要稍後再獲取另一個參數。你可以解決,通過做這樣的事情在函數內部:
(let [x 10
f #(- % x)]
f)
我用他們所有的時間,但它們的使用是如此簡單,很難認爲是不做作的例子。
我在Lorenz Systems最近的一個項目中發現了這個問題。 Hue-f是一個函數,當給定Lorenz系統的x,y和z座標時,返回一定的色調來爲該線條的該部分着色。它形成了隨機生成一個封閉:
(def rand-gen (g/new-rand-gen 99))
(def hue-f #(co/test1 % %2 %3 (g/random-double 1 1.05 rand-gen) 1.7))
;^Closure
雖然在這種情況下,關閉是不必要的,因爲rand-gen
是全球性的反正。如果我想「讓必要的」,我可以改變它的東西,如:
(def hue-f
(let [rand-gen (g/new-rand-gen 99)]
#(co/test1 % %2 %3 (g/random-double 1 1.05 rand-gen) 1.7)))
;^Closure
(我覺得我得到了括號那裏的Lisp是很難寫的「自由之手」
Upvoting,因爲我只是喜歡舊的讓lambda。 – yorodm
閉包允許你捕獲某些狀態以備後用,即使在創建狀態的上下文不可觸及的情況下,它幾乎就像是一個「門戶」:你通過門戶伸手,你可以抓住在某些不屬於你當前的領域
因此,最有用的封閉案例是當你需要控制或訪問某些東西,但沒有原始的處理。
一個用例如下:比方說,我想創建一個自行完成某項工作的線程,但我希望能夠「通話」該線程並說,「您的工作已經完成,請停止你正在做的事情。「
(defn do-something-forever
[]
(let [keep-going (atom true)
stop-fn #(reset! keep-going false)]
(future (while @keep-going
(println "Doing something!")
(Thread/sleep 500))
(println "Stopping..."))
stop-fn))
有幾種方法來完成此(顯式地創建一個線程並中斷它,例如),但此方法返回一個函數,它,進行評價時,修改所述封閉變量keep-going
使得的值在完全不同的上下文中運行的線程會看到更改並停止循環。
就好像我伸手通過門戶並翻轉開關;沒有關閉,我沒有辦法抓住keep-going
。
閉合,捲曲和部分應用在語言的可組合性中起着重要作用。在設計上,它提供了一定程度的靈活性,以構建適應預期結果的功能,這些功能不是靜態定義的。
術語閉包來自於能夠「關閉」一個範圍內的變量,並將閉合的超過變量的值超出它所聲明的範圍。
閉包可以像任何其他數據/函數引用一樣傳遞。
而且,與函數不同,閉包在聲明時不進行評估。我忘記了這個lambda微積分術語,但它是推遲結果生成的一種方式。
可以聲明像匿名函數的封閉(使用的(fn []...)
或#(...)
速記的一個不同之處在於區別於拉姆達是如果它關閉在通過更高級別的範圍通過在變量中。
一個很好的例子採用封閉是當你從一個函數返回一個函數內部函數仍然「記住」這是附近創建的變量
例:
(defn get-caller [param1 param2]
(fn [param3]
(call-remote-service param1 param2 param3)))
(def caller (get-caller :foo 42))
(def result (caller "hello"))
更好的(和真實的)示例可能是廣泛用於HTTP處理的中間件模式。假設您想要爲每個HTTP請求分配一個用戶。這裏是一箇中間件:
(defn auth-middleware [handler]
(fn [request] ;; inner function
(let [user-id (some-> request :session :user_id)
user (get-user-by-id user-id)]
(handler (assoc request :user user)))))
A handler
參數是一個HTTP處理程序。現在,每個請求都會有一個:user
字段,填充用戶數據或nil
值。
現在你包與中間件(的Compojure語法)的處理程序:
(GET "/api" request ((auth-middleware your-api-handler) request))
因爲你的內部函數引用handler
變量,您使用的是關閉。
你從來沒有寫過map
的函數或filter
的一個函數來描述環境嗎?
(let [adults (filter #(>= (:age %) 21) people)] ...)
...或者,給謂詞名稱:
(def adult? #(>= (:age %) 21))
這將關閉在不斷21
。它可能來自國家或活動領域(婚姻,刑事責任,投票權)或其他任何領域。
除了其他答案,緩存通常是使用閉包的好地方。如果你能負擔得起的內存緩存,最簡單的方法之一是將緩存在封閉:
(defn cached-get-maker []
(let [cache (volatile nil)]
(fn [params]
(if @cache
@cache
(let [result (get-data params)]
(vreset! cache result)
result)))))
根據執行的情況下,你可以使用原子代替揮發性的。 Memoizing也是封閉式的,是一種專門的緩存技術。只是你不需要自己實現它,Closure提供memoize
。
對不起,不知道如何在手機上縮進代碼。 – DjebbZ
- 1. Clojure關閉
- 2. Clojure XML流關閉異常
- 3. 關於使用Clojure
- 4. 如何在Windows關閉時關閉FiddlerCore
- 5. 何時關閉bbdd並關閉光標?
- 6. Parent關閉時關閉Python
- 7. 使用Dapper時的關閉連接
- 8. 當MainActivity關閉時使用LocalBroadcastManager的Android
- 9. Vim with vim.fireplace試圖打開Clojure文件時關閉/掛起
- 10. 如何在使用nrepl.el時更新Clojure依賴關係?
- 11. 我如何知道NSWindow是使用關閉按鈕關閉的?
- 12. SQLiteDatabase使用後關閉或不關閉
- 13. 懸停時關閉模式窗口,關閉焦點時關閉
- 14. 何時使用Java servlets打開和何時關閉mysql連接?
- 15. 如何在用戶選擇關閉按鈕時關閉舞臺?
- 16. 如何在使用GNU屏幕時關閉emacs(或vi)後關閉屏幕?
- 17. 如何在特定時間關閉通知,即使應用程序已關閉
- 18. 如何在使用組合(java)時實現關閉開關?
- 19. 使用彈簧啓動執行器關閉mongo時的應用狀態關閉
- 20. 使用Bootstrap CSS即時關閉Modals
- 21. 使用剃鬚刀時關閉WebFormViewEngine?
- 22. 使用LdapTemplate時LDAP連接未關閉
- 23. 當使用ABNewPersonViewController時關閉UIPopoverController
- 24. 使用Resharper時關閉Visual Studio建議?
- 25. 強制關閉時使用SharedPreferences
- 26. 當關閉頁面時使用javascript pompt
- 27. 關機時關閉電源時打開電源時關閉
- 28. Clojure:在一個慣用的Clojure時尚中使用java.util.HashMap
- 29. 關閉時
- 30. JavaScript時關閉
我真的不認爲這與Clojure有很大關係。無論語言如何,我希望關閉的用例都是相同的。 – Carcigenicate
@Carcigenicate公平,當然,以一種已知的語言來請求示例。標籤顯示OP意識到這個問題更廣泛地適用。沒有「Clojure」,標題會更好。 – Thumbnail
當然,但我想讓那些不熟悉閉包的Clojure初學者更容易理解這個概念。 –