6

我想我会发布这个,因为我在没有真正了解发生了什么的情况下通过猜测来工作,我认为如果有人解释它可能会有所帮助。

我了解如何在 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是我希望将值绑定到的变量的名称,但上面的映射不是有效的 Clojure 映射。它是如何工作的?

我还知道这是针对 Ring 请求映射(以某种方式由defroutes宏提供)进行评估的,但上面的表达式不是函数或宏定义,那么它如何“存在”为我的代码中的有效表达式?宏参数的正常规则是否有某种暂停?我一直无法找到这个非 Lisp'er 可以理解的解构形式的语法定义。

4

2 回答 2

3

该映射是一个有效的解构映射。在绑定名称的任何地方,都可以使用解构。您可以在 a 中执行相同的操作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 究竟对引擎盖下的那张地图做了什么,但我认为它会将它扔进一个 let 或类似的东西中,就像我上面演示的那样。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 和延迟评估之外,这里并没有什么特别之处。

于 2010-11-03T16:43:14.913 回答
1

解构发生在绑定形式中,对于映射解构,要绑定的 var 位于左侧,键位于右侧:

用户=>(让 [{a :foo} {:foo :bar}]
用户=* a)
:酒吧

Compojure 在幕后做一个绑定表单,因此您在上面使用的地图解构表单有效地变成了类似的东西:

(让 [{{some_arg "some_arg"} :params} 请求]
  ...)

request隐式提供的地图在哪里。

矢量版本(例如,[some_arg])是一种替代方案,它只绑定:params到请求中包含的地图。

于 2010-11-03T16:44:42.130 回答