2016-09-17 16 views
7

Tôi đang xem qua cuốn sách phát triển web clojure và nó cho tôi chuyển đối tượng điều khiển (được định nghĩa bên dưới) thay vì hàm chính vì hàm này sẽ thay đổi động (đây là những gì wrap-reload).Khi nào sử dụng một biến thay vì một hàm?

Cuốn sách này nói:.

"Lưu ý rằng chúng ta phải tạo ra một var từ xử lý theo thứ tự cho middleware này để làm việc này là cần thiết để đảm bảo rằng các đối tượng Var chứa hàm xử lý hiện nay được trả lại Nếu chúng ta sử dụng trình xử lý thay vào đó thì ứng dụng sẽ chỉ thấy giá trị ban đầu của hàm và các thay đổi sẽ không được phản ánh. " Tôi thực sự không hiểu điều này có nghĩa là gì, vars có tương tự như c con trỏ không?

(ns ring-app.core 
    (:require [ring.adapter.jetty :as jetty] 
      [ring.util.response :as response] 
      [ring.middleware.reload :refer [wrap-reload]])) 

(defn handler [request] 
    (response/response 
    (str "<html>/<body> your IP is: " (:remote-addr request) 
     "</body></html>"))) 

(defn wrap-nocache [handler] 
    (fn [request] 
    (-> request 
     handler 
     (assoc-in [:headers "Pragma"] "no-cache")))) 

Đây là cuộc gọi handler:

(defn -main [] 
    (jetty/run-jetty 
    (wrap-reload (wrap-nocache (var handler))) 
    {:port 3001 
    :join? false})) 

Trả lời

11

Vâng, var cũng tương tự như một con trỏ C. Đây là tài liệu kém.

Giả sử bạn định nghĩa fred như sau:

(defn fred [x] (+ x 1)) 

Thực tế, có 3 điều ở đây. Trước hết, fred là một biểu tượng. Có sự khác biệt giữa biểu tượng fred (không có dấu ngoặc kép) và từ khóa :fred (được đánh dấu bằng số : char hàng đầu) và chuỗi "fred" (được đánh dấu bằng dấu ngoặc kép ở cả hai đầu). Để Clojure, mỗi người trong số họ bao gồm 4 ký tự; tức là không phải dấu hai chấm của từ khóa lẫn dấu ngoặc kép của chuỗi được bao gồm trong độ dài hoặc thành phần của chúng:

> (name 'fred) 
"fred" 
> (name :fred) 
"fred" 
> (name "fred") 
"fred" 

Sự khác biệt duy nhất là cách chúng được diễn giải. Một chuỗi có nghĩa là đại diện cho dữ liệu người dùng của bất kỳ loại nào. Từ khóa có nghĩa là đại diện cho thông tin kiểm soát cho chương trình, dưới dạng "số ma thuật" như 1 = bên trái, 2 = phải, chúng tôi chỉ sử dụng từ khóa :left:right.

Biểu tượng này có nghĩa là điểm đến điều gì đó, giống như trong Java hoặc C. Nếu chúng ta nói

(let [x 1 
     y (+ x 1) ] 
    (println y)) 
;=> 2 

sau đó x điểm với giá trị 1, y điểm với giá trị 2, và chúng ta thấy kết quả in ra.

dạng (def ...) giới thiệu một số vô hình yếu tố thứ ba, var. Vì vậy, nếu chúng tôi nói

(def wilma 3) 

chúng tôi hiện có 3 đối tượng để xem xét. wilma là một biểu tượng, trỏ đến số var, lần lượt trỏ đến giá trị 3. Khi chương trình của chúng tôi gặp biểu tượng wilma, đó là được đánh giá để tìm số var. Tương tự như vậy, var là được đánh giá để mang lại giá trị 3. Vì vậy, nó giống như một con trỏ 2 cấp của con trỏ trong C.Vì cả hai biểu tượng var được "tự động đánh giá", điều này xảy ra tự động và vô hình và bạn không phải suy nghĩ về var (thực sự, hầu hết mọi người không thực sự biết bước giữa vô hình thậm chí tồn tại).

Đối với chức năng của chúng tôi fred ở trên, một tình huống tương tự tồn tại, ngoại trừ điểm var cho hàm ẩn danh (fn [x] (+ x 1)) thay vì giá trị 3 như với wilma.

Chúng tôi có thể "ngắn mạch" tự động đánh giá của var như:

> (var wilma) 
#'clj.core/wilma 

hoặc

> #'wilma 
#'clj.core/wilma 

nơi người đọc vĩ mô #' (lb-quote) là một cách viết tắt của gọi số (var ...) biểu mẫu đặc biệt. Hãy nhớ rằng một dạng đặc biệt như var là trình biên dịch được tích hợp như 'if' hoặc 'def' và không giống như một hàm thông thường. Biểu mẫu đặc biệt var trả về đối tượng var được gắn vào biểu tượng wilma. REPL clojure in các đối tượng var sử dụng cùng một cách viết tắt, vì vậy cả hai kết quả trông giống nhau.

Một khi chúng ta có đối tượng var, tự động đánh giá bị vô hiệu hóa:

> (println (var wilma)) 
#'clj.core/wilma 

Nếu chúng ta muốn để có được giá trị mà wilma điểm đến, chúng ta cần phải sử dụng var-get:

> (var-get (var wilma)) 
3 
> (var-get #'wilma) 
3 

Điều tương tự cũng hoạt động đối với fred:

> (var-get #'fred) 
#object[clj.core$fred 0x599adf07 "[email protected]"] 
> (var-get (var fred)) 
#object[clj.core$fred 0x599adf07 "[email protected]"] 

nơi #object[clj.core$fred ...] công cụ là cách của Clojure đại diện cho một đối tượng chức năng như một chuỗi.

Đối với máy chủ web, nó có thể thông qua chức năng var? hoặc ngược lại nếu giá trị được cung cấp là hàm xử lý hoặc var trỏ đến hàm điều khiển.

Nếu bạn gõ một cái gì đó như:

(jetty/run-jetty handler) 

kép tự động đánh giá sẽ mang lại đối tượng chức năng xử lý, mà được chuyển cho run-jetty. Nếu, thay vào đó, bạn gõ:

(jetty/run-jetty (var handler)) 

thì var mà chỉ vào đối tượng chức năng xử lý sẽ được chuyển đến run-jetty. Sau đó, run-jetty sẽ phải sử dụng tuyên bố if hoặc tương đương để xác định nội dung đã nhận và gọi (var-get ...) nếu đã nhận được var thay vì chức năng. Do đó, mỗi lần thông qua (var-get ...) sẽ trả về đối tượng mà tại đó var hiện đang trỏ. Vì vậy, các hoạt động var giống như một con trỏ toàn cầu trong C, hoặc một biến "tham chiếu" toàn cầu trong Java.

Nếu bạn vượt qua một đối tượng chức năng để run-jetty, nó tiết kiệm một "con trỏ địa phương" cho đối tượng chức năng và không có cách nào cho thế giới bên ngoài để thay đổi những gì con trỏ địa phương đề cập đến.

Bạn có thể tìm thêm chi tiết ở đây:

7

Hy vọng ví dụ nhỏ này sẽ giúp bạn đi đúng hướng:

> (defn your-handler [x] x) 
#'your-handler 

> (defn wrap-inc [f] 
    (fn [x] 
     (inc (f x)))) 
> #'wrap-inc 

> (def your-app-with-var (wrap-inC#'your-handler)) 
#'your-app-with-var 

> (def your-app-without-var (wrap-inc your-handler)) 
#'your-app-without-var 

> (your-app-with-var 1) 
2 

> (your-app-without-var 1) 
2 

> (defn your-handler [x] 10) 
#'your-handler 

> (your-app-with-var 1) 
11 

> (your-app-without-var 1) 
2 

Trực giác của việc này là khi bạn sử dụng một var khi tạo trình xử lý của bạn, bạn là actu đồng minh đi qua một "container" với một số giá trị, nội dung trong đó có thể được thay đổi trong tương lai bằng cách xác định var có cùng tên. Khi bạn không sử dụng var (như trong your-app-without-var), bạn đang chuyển giá trị hiện tại của "vùng chứa" này, không thể định nghĩa lại theo bất kỳ cách nào.

7

Có một vài câu trả lời hay. Chỉ muốn thêm bối cảnh này:

(defn f [] 10) 
(defn g [] (f)) 
(g) ;;=> 10 
(defn f [] 11) 

;; -Dclojure.compiler.direct-linking=true 
(g) ;;=> 10 

;; -Dclojure.compiler.direct-linking=false 
(g) ;;=> 11 

Vì vậy, khi direct linking đang bật, các gián tiếp thông qua một var được thay thế bằng một invocation tĩnh trực tiếp. Tương tự như tình huống với trình xử lý, nhưng sau đó với mọi yêu cầu var, trừ khi bạn chỉ định rõ ràng một var, như:

(defn g [] (#'f)) 
Các vấn đề liên quan