我想我会发布这篇文章,因为我在没有真正理解正在发生的事情的情况下通过猜测来完成工作,我认为如果有人解释它可能会有所帮助。
我理解如何在Compojure处理程序中获取:params map的元素:
(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映射。它是如何工作的?
我还得到这是根据Ring请求映射(由defroutes
宏以某种方式提供)进行评估,但上面的表达式不是函数或宏定义,所以它如何“存在”为我的代码中的有效表达式?宏观参数的正常规则是否存在某种暂停?我一直无法找到这个非Lisp'er可理解的解构形式语法的定义。
答案 0 :(得分:3)
地图是有效的解构图。在绑定名称的任何位置,您都可以使用解构。您可以在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 - named arguments
有很多博客帖子展示了解构,包括this一个。我不确定哪一个会成为一个可以学习的规范场所。
我并没有假装知道对于那个地图下的地图究竟是什么组成的,但是我认为它会把它扔进一个像我上面演示过的类似的东西。 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 :(得分:1)
销毁发生在绑定表单中,对于映射解构,要绑定的var位于左侧,键位于右侧:
user=> (let [{a :foo} {:foo :bar}] user=* a) :bar
Compojure在幕后做了一个绑定表单,所以你在上面使用的地图解构表格实际上变成了这样的东西:
(let [{{some_arg "some_arg"} :params} request] ...)
request
是隐式提供的地图。
矢量版本(例如[some_arg]
)是一种替代方案,它只与请求中包含的:params
地图绑定。