clojure.core содержит макросы bindings и with-redefs. Глядя на строки документации и примеры на clojuredocs.org, кажется, что они делают что-то очень похожее. В чем разница и какой из них я должен использовать в каких ситуациях?
Clojure: привязка против with-redefs
comment
Также см. этот вопрос: 15748334#15748334" title="какой смысл определять что-то как динамическое, когда вам не нужно определять"> stackoverflow.com/questions/15747774/
- person Alex   schedule 22.11.2013
Ответы (1)
Clojure Vars может иметь локальные привязки потока. binding
использует их, в то время как with-redefs
фактически изменяет корневую привязку (которая чем-то похожа на значение по умолчанию) var.
Еще одно отличие состоит в том, что binding
работает только для :dynamic
переменных, а with-redefs
работает для всех переменных.
Примеры:
user=> (def ^:dynamic *a* 1)
#'user/*a*
user=> (binding [*a* 2] *a*)
2
user=> (with-redefs [*a* 2] *a*)
2
user=> (binding [*a* 2] (doto (Thread. (fn [] (println "*a* is " *a*))) (.start) (.join)))
*a* is 1
#<Thread Thread[Thread-2,5,]>
user=> (with-redefs [*a* 2] (doto (Thread. (fn [] (println "*a* is " *a*))) (.start) (.join)))
*a* is 2
#<Thread Thread[Thread-3,5,]>
Вы можете использовать (недокументированный) binding-conveyor-fn
для передачи локальных привязок потока в новые потоки:
user=> (binding [*a* 2] (doto (Thread. (#'clojure.core/binding-conveyor-fn (fn [] (println "*a* is " *a*)))) (.start) (.join)))
*a* is 2
#<Thread Thread[Thread-5,5,]>
person
opqdonut
schedule
22.11.2013
Именно поэтому
with-redefs
предназначен для использования в тестах (где вы можете захотеть войти и заглушить функцию), а binding
также может быть полезен в рабочем коде.
- person Peeja; 29.09.2014
@Peeja, спасибо, другими словами,
with-redefs
никогда не следует использовать в многопоточных контекстах?
- person Erik Kaplun; 11.06.2019
@opqdonut по состоянию на июнь 2019 года в документации Vars есть раздел Обязательная передача, в котором выделены
future
, send
, send-off
и pmap
как имеющие возможности связывания перевозки — значит ли это, что binding-conveyor-fn
больше не нужен?
- person Erik Kaplun; 11.06.2019
@ErikKaplun,
binding-conveyor-fn
не нужен, если вы используете упомянутые вами функции. Однако, если вы создаете потоки с помощью (Thread. ...)
, он вам все равно понадобится.
- person Miikka; 14.01.2020