Невозможно изменить / установить привязку корня из: [some-def] с установленным в Clojure

Я не мог установить значение моей динамической переменной на новое.

(def *pop* true)

(set! *pop* false)

=> IllegalStateException Can't change/establish root binding of: *pop* with set  clojure.lang.Var.set (Var.java:221)


Также я добавил ^:dynamic, который тоже не работал.

(def ^:dynamic *pop* true)

(set! *pop* false)

=> IllegalStateException Can't change/establish root binding of: *pop* with set  clojure.lang.Var.set (Var.java:221)


Но, с другой стороны, этот код работает,(clojure core var -> *warn-on-reflection*)

(set! *warn-on-reflection* true)
=> true

*warn-on-reflection*
=> true

(set! *warn-on-reflection* false)
=> false

*warn-on-reflection*
=> false

2 ответа

Решение

Динамические переменные могут быть только set! внутри binding объем. Так что просто звоню set! на *pop* не будет работать - вы должны находиться в динамической области привязки привязки где-то в стеке вызовов выше.

(def ^:dynamic *pop* true)
(binding [*pop* *pop*]  ;; defaulted to the root binding value
  (set! *pop* false)    ;; ok, because in dynamic binding scope
  (println *pop*))      ;; prints "false" (inside per-thread dynamic binding)
(println *pop*)         ;; prints "true" (root value)

Обратите внимание, что часть "динамического объема" означает, что в binding вы можете делать произвольные вложенные вызовы и при этом иметь доступ к установке и чтению значения для потока *pop*,

относительно *warn-on-reflection*Это выглядит как особое поведение, но на самом деле оно точно такое же, за исключением скрытого от глаз. Сам REPL создает динамическую область привязки вокруг eval каждого оператора REPL с привязками для жестко запрограммированного набора динамических переменных, из которых *warn-on-reflection* это один. Вы можете найти этот набор привязок здесь.

Вы можете использовать alter-var-root для изменения корневых переменных.

user=> (def *pop* true)
Warning: *pop* not declared dynamic ...
#'user/*pop*

user=> (alter-var-root #'*pop* (constantly false))
false

user=> *pop*
false
Другие вопросы по тегам