2016-08-10 5 views

ответ

5

Можно ли предопределённая динамика неявно завернутым в обязательной форме пути выполнения? Потому что это работает, например:

user=> (def ^:dynamic *x*) 
user=> (binding [*x* false] (set! *x* true)) 
true 
user=> 

Единственное, что следует отметить, что в документации прямо говорит, что его ошибка, чтобы попытаться изменить корень связывания через set! см:

http://clojure.org/reference/vars

Это также возможно, что встроенные функции рассматриваются в исключительных случаях, например, если вы посмотрите на метаданные х:

user=> (meta #'*x*) 
{:dynamic true, :line 1, :column 1, :file "/private/var/folders/8j/ckhdsww161xdwy3cfddjd01d25k_1q/T/form-init5379741350621280680.clj", :name *x*, :ns #object[clojure.lang.Namespace 0x6b8f00 "user"]} 

Он отмечен как динамичные, в то время как *warn-on-reflection* не помечен как динамический, но до сих пор работает в обязательной форме:

user=> (meta #'*warn-on-reflection*) 
{:added "1.0", :ns #object[clojure.lang.Namespace 0x377fc927 "clojure.core"], :name *warn-on-reflection*, :doc "When set to true, the compiler will emit warnings when reflection is\n needed to resolve Java method calls or field accesses.\n\n Defaults to false."} 
user=> (binding [*warn-on-reflection* true] (set! *warn-on-reflection* false)) 
false 
user=> 

Предположительно это для обратной совместимости, так как в более ранних версиях Clojure вары с наушниками (звездами в каждой стороне) были по соглашению. Но в любом случае это просто показывает, что встроенные элементы обрабатываются несколько иначе.

Теперь я решил взять это немного дальше, и grep исходный код Clojure, ищет warn-on-reflection, что приводит меня к постоянному WARN_ON_REFLECTION, что приводит меня к строкам кода, как это в RT.java:

https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L467

Var.pushThreadBindings(
     RT.mapUniqueKeys(CURRENT_NS, CURRENT_NS.deref(), 
       WARN_ON_REFLECTION, WARN_ON_REFLECTION.deref() 
       ,RT.UNCHECKED_MATH, RT.UNCHECKED_MATH.deref())); 

что приводит меня к мысли, что мое первоначальное предположение было верным, что некоторые специальные глобальные вары неявно обернуты в потоке локального связывания.

EDIT:

Как уже упоминалось в комментариях, вы можете использовать clojure.core/push-thread-bindings, но обязательно следовать советам документации и завернуть в Try/улов /, наконец, pop-thread-bindings в конце концов блока. И в этот момент вы бы только что внедрили binding (например, запустите (source binding) в repl), что, вероятно, почему документ явно предупреждает, что push-thread-bindings является низкоуровневой функцией, а binding предпочтительнее.

+0

Теперь я вижу, спасибо! Также [вот почему] (https://github.com/clojure/clojure/blob/d920ada9fab7e9b8342d28d8295a600a814c1d8a/src/jvm/clojure/lang/RT.java#L228) Я не смог найти определение '* warn-on- отражение * 'в' clojure.core'. – OlegTheCat

+0

Возможно, вы захотите добавить, что вы, возможно, можете сделать свою собственную динамическую переменную одинаковой с https://clojuredocs.org/clojure.core/push-thread-bindings. – coredump

4

просматривал документ, вы найдете

user=> (doc thread-bound?) 
------------------------- 
clojure.core/thread-bound? 
([& vars]) 
    Returns true if all of the vars provided 
    as arguments have thread-local bindings. 
    Implies that set!'ing the provided vars will succeed. 
    Returns true if no vars are provided. 

в частности:

Подразумевается, что набор!«ИНГ предоставленные ВАР преуспеет

так, то это означает, что вы можете проверить, если set! можно следующим образом:

user=> (thread-bound? #'*x*) 
false 
user=> (thread-bound? #'*unchecked-math*) 
true  

, который означает, что вы можете только set! нить переплете вары, которые ваш *x* не является (все же).


PS: в Kevins ответ вы увидите Var.pushThreadBindings который presumely на самом деле, как имеющиеся clojure.core/push-thread-bindings - если вы wan't копать глубже.

1

Согласно reference on Vars, вы можете использовать только set! назначение на резьбовой переплет Варса:

В настоящее время, это ошибка, чтобы попытаться установить корень связывание вара с помощью набора !, т.е. вар присваивания являются поточно-локальными. Во всех случаях возвращается значение expr .

Однако встроенные динамические вары как *warn-on-reflection* имеют внутрипотоковые привязки, таким образом, вы можете свободно использовать set! на них:

(thread-bound? #'*unchecked-math*) 
=> true 

тогда (def ^:dynamic *x*) только создает корень связывания:

(thread-bound? #'*x*) 
=> false 

Макрос binding создает новую область для динамического Var; на низком уровне он временно 'pushes' привязывает значения данных Vars к текущему потоку, а затем 'pops' их при выходе из тела макроса.

(binding [*x* 1] 
    (thread-bound? #'*x*)) 
=> true 

(binding [*x* 1] 
    (set! *x* 2)) 
=> 2 

 Смежные вопросы

  • Нет связанных вопросов^_^