Когда использовать Var вместо функции?

Я просматриваю книгу разработки web-страниц clojure, и она говорит мне передать обработчик (определенный ниже) объект var вместо самой функции, потому что функция будет динамически изменяться (это то, что делает перезагрузка).

В книге говорится:

«Обратите внимание, что мы должны создать var из обработчика, чтобы это промежуточное программное обеспечение работало. Это необходимо для обеспечения возврата объекта Var, содержащего текущую функцию обработчика. Если бы мы использовали обработчик, вместо этого приложение увидело бы только первоначальное значение функции и изменения не отражались бы ». Я действительно не понимаю, что это значит, являются ли похожа на vars?

(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 "/ your IP is: " (:remote-addr request) ""))) (defn wrap-nocache [handler] (fn [request] (-> request handler (assoc-in [:headers "Pragma"] "no-cache")))) 

Вот вызов обработчика:

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

Да, var похож на C-указатель. Это плохо документировано.

Предположим, что вы определяете fred следующим образом:

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

На самом деле здесь есть три вещи. Во-первых, fred является символом. Существует различие между символом fred (без кавычек) и ключевым словом :fred (помечено символом fred : char) и строкой "fred" (отмечена двойной кавычкой на обоих концах). Для Clojure каждый из них состоит из 4 символов; т.е. ни двоеточие ключевого слова, ни двойные кавычки строки не includeся в их длину или состав:

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

Единственная разница в том, как они интерпретируются. Строка предназначена для представления пользовательских данных любого типа. Ключевое слово предназначено для представления управляющей информации для программы в читаемой форме (в отличие от «магических чисел», таких как 1 = left, 2 = right, мы просто используем ключевые слова :left и :right .

Символ предназначен для указания на вещи, как на Java или C. Если мы скажем

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

то x указывает на значение 1, y указывает на значение 2, и мы видим, что результат напечатан.

форма (def ...) вводит невидимый третий элемент, var . Поэтому, если мы скажем

 (def wilma 3) 

теперь у нас есть 3 объекта. wilma – это символ, который указывает на var , который, в свою очередь, указывает на значение 3 . Когда наша программа встречает символ wilma , оценивается, чтобы найти var . Аналогично, var оценивается так, чтобы получить значение 3. Таким образом, это похоже на двухуровневую направленность указателей в C. Поскольку и символ, и var «автоматически оцениваются», это происходит автоматически и невидимо, и вы не должны думать о var (действительно, большинство людей не знают, что невидимый средний шаг даже существует).

Для нашей функции fred выше аналогичная ситуация существует, за исключением того, что var указывает на анонимную функцию (fn [x] (+ x 1)) вместо значения 3 как с wilma .

Мы можем «закоротить» автоматическую оценку var как:

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

или

 > #'wilma #'clj.core/wilma 

где макрос читателя #' (фунтовая кавычка) является сокращенным способом вызова специальной формы (var ...) . Имейте в виду, что специальная форма, такая как var является встроенным компилятором, например «if» или «def», и не является обычной функцией. Специальная форма var возвращает объект var прикрепленный к символу wilma . Clojure REPL печатает объект var с использованием той же стенографии, поэтому оба результата выглядят одинаково.

Когда у нас есть объект var, автоматическая оценка отключена:

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

Если мы хотим получить значение, на wilma указывает wilma , нам нужно использовать var-get :

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

То же самое работает для Фреда:

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

где #object[clj.core$fred ...] – это способ Clojure представлять объект функции в виде строки.

Что касается веб-сервера, он может узнать через var? или иначе, если поставляемое значение является функцией обработчика или var, которая указывает на функцию обработчика.

Если вы напечатаете что-то вроде:

 (jetty/run-jetty handler) 

двойная автоматическая оценка даст объект функции обработчика, который передается в run-jetty . Если вместо этого вы вводите:

 (jetty/run-jetty (var handler)) 

то var который указывает на объект функции обработчика, будет передан в run-jetty . Затем run-jetty должен будет использовать оператор if или эквивалент, чтобы определить, что он получил, и вызвать (var-get ...) если он получил var вместо функции. Таким образом, каждый раз через (var-get ...) возвращается объект, на который указывает данный параметр var . Таким образом, var действует как глобальный указатель на C или глобальная «ссылочная» переменная в Java.

Если вы передаете объект функции run-jetty , он сохраняет «локальный указатель» на объект функции, и для внешнего мира нет способа изменить то, на что ссылается локальный указатель.

Вы можете найти более подробную информацию здесь:

Надеюсь, этот небольшой пример поможет вам:

 > (defn your-handler [x] x) #'your-handler > (defn wrap-inc [f] (fn [x] (inc (fx)))) > #'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 

Интуиция для этого – когда вы используете var при создании своего обработчика, вы фактически передаете «контейнер» с некоторым значением, содержимое которого можно изменить в будущем, указав var с тем же именем. Когда вы не используете var (например, в your-app-without-var ), вы передаете текущее значение этого «контейнера», которое никак не может быть переопределено.

Уже есть несколько хороших ответов. Просто хотел добавить это оговорку:

 (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 

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

 (defn g [] (#'f)) 
  • Почему некоторые веб-сайты недоступны с одного компьютера в сети?
  • скептически отслеживает, как очистить данные с этого сайта (используя R)
  • Как подключиться через HTTPS с помощью Jsoup?
  • Как вручную добавить в Internet Explorer список защиты слежения (TPL), который не находится на веб-сайте галереи Internet Explorer?
  • Программное обеспечение для очистки экрана, которое будет перемещаться по страницам
  • Суперclass «javax.servlet.http.HttpServlet» не найден на пути сборки Java
  • Откройте прямой файл на жестком диске из Firefox (файл: ///)
  • Chrome: выбор ссылки путем выполнения поиска по ее тексту.
  • Веб-хостинг дома на старом оборудовании
  • Извлечение данных с карты
  • IE9 блокирует загрузку кросс-оригинального веб-шрифта
  • Interesting Posts

    Импорт векторного файла EPS в Microsoft Word без потери качества

    отменить порядок символов в строке

    Если вы всегда используете «int» для чисел в C, даже если они неотрицательны?

    Как установить Linux на динамический диск без потери конфигурации диска?

    this.getClass (). getClassLoader (). getResource (“…”) и NullPointerException

    Java 256-битное шифрование на основе AES на основе паролей

    Как создать банку для проекта библиотеки Android

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

    Бесплатная программа для синхронизации папки с FTP?

    Как принудительно распространять изменения роли для пользователей с помощью ASP.NET Identity 2.0.1?

    Трассировка стека Windows C ++ из запущенного приложения

    Инструмент Windows 7/8 для усиления звука / эквивалента pavucontrol?

    Множественное затухание изображения в CSS – без (java) скрипта

    Переключение fragmentов внутри вкладки

    Как вы получаете имя переменной, поскольку оно было физически напечатано в его объявлении?

    Давайте будем гением компьютера.