Разрушающие формы и Compojure? - PullRequest
6 голосов
/ 03 ноября 2010

Я думал, что отправлю это, потому что заставил его работать на догадках без реального понимания того, что происходит, и я подумал, что было бы полезно, если бы кто-то объяснил это.

Я понимаю, какполучить элемент карты: 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), но приведенное выше выражение не является определением функции или макроса, поэтому как оно может «существовать» как допустимое выражение в моем коде? Есть ли какая-то приостановка нормальногоправила для макро аргументов?Мне не удалось найти определение синтаксиса форм деструктуризации, понятное этому не-Лисперу.

Ответы [ 2 ]

3 голосов
/ 03 ноября 2010

Карта является действующей картой разрушения. В любом месте, где вы связываете имена, вы можете использовать деструктуризацию. Вы можете сделать то же самое в 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 - именованные аргументы

Есть много сообщений в блогах, демонстрирующих деструктуризацию, включая эту одну. Я не уверен, в каком из них можно было бы поучиться.

Я не претендую на то, чтобы знать, что именно делает compojure с этой картой под капотом, но я предполагаю, что она бросает ее в пустоту или что-то подобное, как я продемонстрировал выше. 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 и отложенной оценки.

1 голос
/ 03 ноября 2010

Разрушение происходит в пределах формы связывания, а для разрушения карты связываемая переменная находится слева, а клавиша справа:

user=> (let [{a :foo}  {:foo :bar}]
user=*   a)
:bar

Compojure создает связующую форму за кулисами, поэтому форма разрушения карты, которую вы использовали выше, фактически превращается в нечто вроде:

(let [{{some_arg "some_arg"} :params}  request]
  ...)

Где request - неявно предоставленная карта.

Векторная версия (например, [some_arg]) - это альтернатива, которая просто привязывается к карте :params, содержащейся в запросе.

...