2016-08-10 16 views

Trả lời

5

Có thể các động dựng sẵn được ngầm bọc trong một hình thức ràng buộc bởi thời gian chạy? Bởi vì việc này, ví dụ:

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

Một điều cần lưu ý là các tài liệu một cách rõ ràng nói rằng một lỗi của mình để thử và sửa đổi gốc rễ ràng buộc qua set!, xem:

http://clojure.org/reference/vars

Đó là cũng có thể các nội trang được xử lý đặc biệt, ví dụ: nếu bạn xem siêu dữ liệu của 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"]} 

Nó đánh dấu là năng động, trong khi *warn-on-reflection* không được đánh dấu như năng động nhưng vẫn hoạt động trong một hình thức ràng buộc:

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=> 

Có lẽ đây là để tương thích ngược bởi vì trong phiên bản trước của clojure vars với earmuffs (ngôi sao trong mỗi bên) là năng động theo quy ước. Nhưng dù sao, điều này chỉ cho thấy rằng nội trang được xử lý hơi khác nhau.

Bây giờ, tôi đã quyết định để thực hiện việc này một chút nữa, và grep mã nguồn của clojure, tìm kiếm warn-on-reflection, dẫn tôi đến liên tục WARN_ON_REFLECTION, dẫn tôi tới dòng mã như thế này trong 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())); 

dẫn tôi tin rằng giả định ban đầu của tôi là đúng, rằng nhất định vars toàn cầu đặc biệt được mặc nhiên được bao bọc trong một thread địa phương ràng buộc.

EDIT:

Như đã đề cập trong một chú thích, bạn có thể sử dụng clojure.core/push-thread-bindings, nhưng hãy chắc chắn để làm theo lời khuyên của các tài liệu và quấn trong try/catch/finally với pop-thread-bindings trong khối finally. Và tại thời điểm đó, bạn sẽ chỉ được triển khai lại binding (ví dụ: chạy (source binding) khi phát lại), đó có thể là lý do tại sao tài liệu cảnh báo rõ ràng rằng push-thread-bindings là chức năng cấp thấp và cần ưu tiên binding.

+0

Bây giờ tôi thấy, cảm ơn! Ngoài ra [đó là lý do] (https://github.com/clojure/clojure/blob/d920ada9fab7e9b8342d28d8295a600a814c1d8a/src/jvm/clojure/lang/RT.java#L228) Tôi không thể tìm thấy định nghĩa '* cảnh báo-on- phản ánh * 'trong' clojure.core'. – OlegTheCat

+0

Bạn có thể muốn thêm rằng bạn có thể làm cho biến động của riêng bạn hoạt động tương tự với https://clojuredocs.org/clojure.core/push-thread-bindings. – coredump

4

perusing doc, bạn sẽ tìm thấy

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. 

đặc biệt:

ngụ ý rằng thiết lập!'Ing các vars cung cấp sẽ thành công

vậy, điều này có nghĩa là bạn có thể kiểm tra nếu set! thể như sau:

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

có nghĩa là bạn chỉ có thể set! vars thread-ràng buộc, mà *x* của bạn không phải là (chưa).


PS: ở Kevins câu trả lời bạn sẽ thấy Var.pushThreadBindings mà presumely là thực sự sẵn như clojure.core/push-thread-bindings - nếu bạn wan't để đào sâu hơn.

1

Theo reference on Vars, bạn chỉ có thể sử dụng set! dự thi đúng vars thread-ràng buộc:

Hiện nay, nó là một lỗi cố gắng để thiết lập các rễ ràng buộc của một var sử dụng bộ !, ví dụ var bài tập là chủ đề địa phương. Trong mọi trường hợp, giá trị của expr được trả về.

Tuy nhiên, được xây dựng trong vars động như *warn-on-reflection* có bindings thread-địa phương, do đó bạn có thể tự do sử dụng set! trên chúng:

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

trong khi (def ^:dynamic *x*) chỉ tạo ra một thư mục gốc ràng buộc:

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

Macro binding tạo phạm vi mới cho Biến động; ở mức thấp, nó temprorarily 'pushes' giá trị ràng buộc của các Vars đã cho cho luồng hiện tại, và sau đó 'pops' chúng khi thoát khỏi phần thân của macro.

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

(binding [*x* 1] 
    (set! *x* 2)) 
=> 2 
Các vấn đề liên quan