我想我会发布这个,因为我通过猜测来工作,而没有真正了解发生了什么,我认为如果有人解释它可能会有所帮助。
我了解如何在 Compojure 处理程序中获取 :params 映射的元素:
(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
是我希望将值绑定(bind)到的变量的名称,但上面的映射不是有效的 Clojure 映射。它是如何工作的?我还知道这是针对 Ring 请求映射(由
defroutes
宏提供的)评估的,但上面的表达式不是函数或宏定义,所以它如何“存在”为我的代码中的有效表达式?宏参数的正常规则是否有某种暂停?我一直无法找到这个非 Lisp'er 可以理解的解构形式的语法定义。
最佳答案
该映射是一个有效的解构映射。在绑定(bind)名称的任何地方,都可以使用解构。你可以在 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"]
我在命名参数的上下文中写了一篇关于 map 解构的文章,但它适用于这里。您可能会发现这很有用:Clojure - named arguments
有很多博客文章展示了解构,包括 this一。我不确定哪一个会是一个典型的学习场所。
我不会假装知道 compojure 到底对引擎盖下的那张 map 做了什么,但我认为它会将它扔进一个 let 或类似的东西中,就像我上面演示的那样。 GET 是一个宏,因此它不必评估您传递给它的 map ,这就是为什么除非它评估它,否则您不会收到错误。
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 和延迟评估之外,这里并没有什么特别之处。
关于clojure - 解构形式和组合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4089162/