为什么我可以这样做:
> (set! *unchecked-math* true)
true
> (set! *warn-on-reflection* false)
false
但不能这样做:
> (def ^:dynamic *x*)
#'user/*x*
> (set! *x* 1) ;; no luck, exception!
答案 0 :(得分:5)
内置动态是否可能被运行时隐式包装在绑定形式中?因为这有效,例如:
user=> (def ^:dynamic *x*)
user=> (binding [*x* false] (set! *x* true))
true
user=>
有一点需要注意的是,文档明确表示尝试通过set!
修改根绑定是错误的,请参阅:
http://clojure.org/reference/vars
也可能会异常处理内置函数,例如,如果您查看x的元数据:
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()));
这让我相信我最初的假设是正确的,某些特殊的全局变量被隐式包装在线程局部绑定中。
编辑:
如评论中所述,您可以使用clojure.core/push-thread-bindings
,但请务必遵循文档的建议,并在finally块中使用pop-thread-bindings
包装try / catch / finally。此时您将重新实现binding
(例如,在repl处运行(source binding)
),这可能是文档明确警告push-thread-bindings
是低级函数的原因,{ {1}}应该是首选。
答案 1 :(得分: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
,如果您不想深入挖掘,那么clojure.core/push-thread-bindings
实际上可以提供let key = "CrawlerDistance"
let request = NSFetchRequest<CrawlerOne>(entityName: "CrawlerOne")
request.returnsObjectsAsFaults = false;
let resultPredicate = Predicate(format: "formUUID = %@" , key)
var compound = CompoundPredicate.init(andPredicateWithSubpredicates: [resultPredicate])
var results:NSArray = try context.executeFetchRequest(request, error:nil)
。
答案 2 :(得分:1)
根据reference on Vars,您只能在线程绑定的变量上使用set!
赋值:
目前,尝试设置var的根绑定是错误的 使用set!,即var赋值是线程局部的。在所有情况下 返回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