Разрушающие формы и Комподжур?
-
28-09-2019 - |
Вопрос
Я думал, что опубликую это, поскольку у меня получилось работать наугад, без реального понимания того, что происходит, и я подумал, что было бы полезно, если бы кто-нибудь объяснил это.
Я понимаю, как получить доступ к элементу карты:params в обработчике Compojure:
(GET "/something" [some_arg] "this is the response body")
или
(GET "/something" {{some_arg "some_arg"} :params} "this is the response body")
хотя я не совсем понимаю, что {some_arg "some_arg"}
часть состоит в том, чтобы делать :(
Я также хотел получить доступ к :remote-addr
часть запроса, а также some_arg
.И в итоге я получил
(GET "/something" {{some_arg "some_arg"} :params ip :remote-addr}
(do-something-with some_arg ip))
Итак, я понимаю, что строки без кавычек some_arg
и ip
это имена переменных, к которым я хочу привязать значения, но приведенная выше карта не является допустимой картой Clojure.Как это работает?
Я также понимаю, что это оценивается по карте кольцевого запроса (которая каким-то образом предоставляется defroutes
макрос) но приведенное выше выражение не является функцией или определением макроса, так как же оно может "существовать" как допустимое выражение в моем коде?Существует ли какая-то приостановка действия обычных правил для аргументов макросов?Я не смог найти определение синтаксиса деструктурирующих форм, понятное этому не-лисперу.
Решение
Карта - это действительная деструктурная карта. В любом месте, где вы связываете имена, вы можете использовать разрушимость. Вы могли бы сделать то же самое в let
, как это:
user=> (let [{{some-arg "some_arg"} :params ip :remote-addr} {:remote-addr "127.0.0.1" :params {"some_arg" "some_value"}}] [ip some-arg])
["127.0.0.1" "some_value"]
Я написал сообщение о деструктурировании отображения в контексте названных аргументов, но это относится здесь. Вы можете найти это полезное: Clojure - названные аргументы
Есть много в блоге, демонстрирующих разрушимость, в том числе это один. Я не уверен, какой из них будет каноническое место для участия.
Я не притворяюсь, что знаешь, что именно компонент делает с этой картой под капотом, но я предполагаю, что это бросает его в пусть или что-то подобное, как я продемонстрировал выше. Get - это макрос, поэтому ему не нужно оценивать карту, которую вы проходите, поэтому вы не получите ошибку, если она не оценивала его.
user=> (defmacro blah [m])
#'user/blah
user=> (blah {a "b" c "d"})
nil
user=> (defn blah [m])
#'user/blah
user=> (blah {a "b" c "d"})
java.lang.Exception: Unable to resolve symbol: a in this context (NO_SOURCE_FILE:9)
Под капотом магия происходит с этой картой, и она передается на функцию, называемую разрушимостью, которая делает разрушительную магию.
Здесь не совсем ничего особенного, кроме обычного макроса / специальной формы FOO и отсроченной оценки.
Другие советы
Разрушение происходит внутри формы привязки, и для деструктурирования карты привязываемый параметр находится слева, а ключ - справа:
user=> (let [{a :foo} {:foo :bar}] user=* a) :bar
Compojure создает форму привязки за кулисами, так что форма деструктурирования карты, которую вы использовали выше, фактически превращается во что-то вроде:
(let [{{some_arg "some_arg"} :params} request] ...)
Где request
является неявно предоставленной картой.
Векторная версия (например,, [some_arg]
), является альтернативой, которая просто противопоставляет :params
карта, содержащаяся в запросе.