veo serum saber que puede plastico para papel otro llama hervir film facial esta escribiendo envolver cuando como cocinar aparece alimentos alguien web clojure var

web - serum - ¿Cuándo usar un Var en lugar de una función?



que es un serum facial (3)

Estoy revisando el libro de desarrollo web clojure y me dice que pase el manejador (definido debajo) del objeto var en lugar de la función en sí porque la función cambiará dinámicamente (esto es lo que hace la recarga de envoltura).

El libro dice:

"Tenga en cuenta que tenemos que crear un var desde el controlador para que este middleware funcione. Esto es necesario para garantizar que se devuelva el objeto Var que contiene la función del controlador actual. Si utilizamos el controlador en su lugar, la aplicación solo vería el el valor original de la función y los cambios no se reflejarían ". Realmente no entiendo lo que esto significa, ¿son vars similares a los punteros c?

(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"))))

Aquí está la llamada del controlador:

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


Esperemos que este pequeño ejemplo lo lleve por buen camino:

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

La intuición para esto es que cuando usa un var al crear su controlador, en realidad está pasando un "contenedor" con algún valor, cuyo contenido puede cambiarse en el futuro definiendo var con el mismo nombre. Cuando no usa var (como en your-app-without-var ) está pasando un valor actual de este "contenedor", que no puede redefinirse de ninguna manera.


Sí, la var es similar a un puntero en C. Esto está mal documentado.

Supongamos que crea una función fred siguiente manera:

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

En realidad hay 3 cosas aquí. En primer lugar, fred es un símbolo. Hay una diferencia entre un símbolo fred (sin comillas) y la palabra clave :fred (marcada por el encabezado : char) y la cadena "fred" (marcada por una comilla doble en ambos extremos). Para Clojure, cada uno de ellos está compuesto por 4 caracteres; es decir, ni los dos puntos de la palabra clave ni las comillas dobles de la cadena se incluyen en su longitud o composición:

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

La única diferencia es cómo se interpretan. Una cadena está destinada a representar datos de usuario de cualquier tipo. Una palabra clave está destinada a representar información de control para el programa, en una forma legible (a diferencia de los "números mágicos" como 1 = izquierda, 2 = derecha, solo usamos palabras clave :left y :right .

Un símbolo está destinado a señalar cosas, como en Java o C. Si decimos

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

luego x apunta al valor 1, y apunta al valor 2, y vemos el resultado impreso.

la forma (def ...) introduce un tercer elemento invisible , la var . Entonces si decimos

(def wilma 3)

ahora tenemos 3 objetos a considerar. wilma es un símbolo, que apunta a una var , que a su vez apunta al valor 3 . Cuando nuestro programa encuentra el símbolo wilma , se evalúa para encontrar la var . Del mismo modo, la var se evalúa para obtener el valor 3. Por lo tanto, es como una indirecta de 2 niveles de punteros en C. Dado que tanto el símbolo como la var son "autoevaluados", esto sucede de forma automática e invisible y usted no tengo que pensar en la var (de hecho, la mayoría de las personas no son realmente conscientes de que el paso intermedio invisible incluso existe).

Para nuestra función fred anterior, existe una situación similar, excepto que var apunta a la función anónima (fn [x] (+ x 1)) lugar del valor 3 como con wilma .

Podemos "cortocircuitar" la autoevaluación de la var como:

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

o

> #''wilma #''clj.core/wilma

donde el lector macro #'' (comilla) es una forma abreviada de llamar a la forma especial (var ...) . Tenga en cuenta que una forma especial como var es un compilador incorporado como ''if'' o ''def'', y no es lo mismo que una función normal. La forma especial var devuelve el objeto var adjunto al símbolo wilma . Clojure REPL imprime el objeto var con la misma taquigrafía, por lo que ambos resultados se ven iguales.

Una vez que tenemos el objeto var, la autoevaluación se desactiva:

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

Si queremos llegar al valor al que apunta wilma , necesitamos usar var-get :

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

Lo mismo funciona para Fred:

> (var-get #''fred) #object[clj.core$fred 0x599adf07 "clj.core$fred@599adf07"] > (var-get (var fred)) #object[clj.core$fred 0x599adf07 "clj.core$fred@599adf07"]

donde el objeto #object[clj.core$fred ...] es la forma en que Clojure representa un objeto de función como una cadena.

Con respecto al servidor web, ¿puede saberlo a través de var? función o de lo contrario si el valor proporcionado es la función del controlador o la var que apunta a la función del controlador.

Si escribe algo como:

(jetty/run-jetty handler)

la doble autoevaluación generará el objeto de función de controlador, que se pasa a run-jetty . Si, en cambio, escribe:

(jetty/run-jetty (var handler))

entonces la var que apunta al objeto de función del controlador se pasará a run-jetty . Luego, run-jetty tendrá que usar una declaración if o equivalente para determinar lo que ha recibido, y llamar (var-get ...) si ha recibido un var lugar de una función. Por lo tanto, cada vez que lo (var-get ...) devolverá el objeto al que apunta var . Entonces, la var actúa como un puntero global en C, o una variable de "referencia" global en Java.

Si pasa un objeto de función a run-jetty , guarda un "puntero local" en el objeto de función y no hay forma de que el mundo exterior cambie a qué se refiere el puntero local.

Puedes encontrar más detalles aquí:


Ya hay un par de buenas respuestas. Solo quería agregar esta advertencia:

(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

Entonces, cuando el enlace directo está activado, la indirección a través de un var se reemplaza con una invocación estática directa. Similar a la situación con el controlador, pero luego con cada invocación de var, a menos que se refiera explícitamente a un var, como:

(defn g [] (#''f))