2010-11-03 74 views
6

我以为我会发布这个,因为我没有真正理解发生的事情,通过猜测工作,我认为如果有人解释它可能会有帮助。解构形式和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"}部分做:在处理的Compojure地图PARAMS :(

我也想访问:remote-addr部分请求以及some_arg我最后用

(GET "/something" {{some_arg "some_arg"} :params ip :remote-addr} 
    (do-something-with some_arg ip)) 

所以,我得到的是不带引号的字符串some_argip是变量的名字,而我想要的值约束,但上面的图是不是一个有效的Clojure地图。它是如何工作的?

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

+1

我错过了一个事实,即GET是一个宏。在下面的答案中解释... – edoloughlin 2010-11-03 16:53:54

回答

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之一。我不确定哪一个可以成为一个规范的学习地点。

我不会假装知道在底层引擎下该地图究竟具有什么功能,但我认为它会将它引入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和延迟评估之外,这里没有任何特别的事情发生。

1

解构发生绑定表单中,并在地图解构了var被束缚在左边,关键是在右边:

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

的Compojure正在做一个绑定形式幕后,所以你在上面使用该地图拆解的形式有效地转变成类似:

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

request是隐含提供的地图。

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