Ответ 1
Я получаю 3 в результате (как и следовало ожидать), когда я запускаю свой первый пример в Clojure 1.4.... вы пробовали это со свежим REPL?
^:dynamic
является инструкцией компилятора Clojure, что символ (как определено с помощью def
) предназначен для динамического восстановления (с помощью binding
).
Пример:
(def foo 1)
(binding [foo 2] foo)
=> IllegalStateException Can't dynamically bind non-dynamic var: ...
(def ^:dynamic bar 10)
(binding [bar 20] bar) ;; dynamically bind bar within the scope of the binding
=> 20
bar ;; check underlying value of bar (outside the binding)
=> 10
Обратите внимание, что binding
имеет динамическую область видимости в вызывающем потоке - любые функции, вызываемые внутри связывания, будут видеть измененное значение bar
(20), но любые другие потоки все равно будут видеть неизменное значение корня 10.
Наконец, несколько пунктов стиля, которые могут вам помочь:
- Обычно считается, что плохая идея заключается в том, чтобы помещать
def
иdefn
в функции, поскольку они влияют на охватывающее пространство имен. Внутри функций вы должны использовать(let [foo bar] ...)
. - Когда вы обнаружите, что хотите использовать
binding
, вам обычно следует рассмотреть вопрос о том, можно ли добиться того же результата, используя функции более высокого порядка.binding
полезен в некоторых контекстах, но, как правило, он не является хорошим способом передачи параметров. Функциональная композиция обычно лучше в долгосрочной перспективе. Причиной этого является то, чтоbinding
создает неявный контекст, необходимый для выполнения вашей функции, и это может быть трудно проверить/отладить.