6

例如 Luminus网站指出

Compojure 路由定义只是接受请求映射并返回响应映射的函数......

(GET "/" [] "Show something")
...

但是组合路由不是函数

(defmacro GET "Generate a `GET` route."
  [path args & body]
  (compile-route :get path args body))

可以使用make-route返回函数的函数,但不允许解构。因此,作为一个函数,您不能使用 compojure 的特殊语法进行解构(即向量),但这会阻止任何形式的解构吗?宏是否给他们带来了性能提升?

(make-route :get "/some_path" some_handler)

不能使用宏包装器将破坏语法传递给函数吗?

4

1 回答 1

8

使用宏的一个原因是用户可以编写函数和符号名称,而不必引用所有内容。以Clojure Cookbook 中的这个例子为例:

; Routing
(defroutes main-routes
  (GET "/"    [] (index))
  (GET "/en/" [] (index))
  (GET "/fr/" [] (index-fr))
  (GET "/:greeting/" [greeting] (view greeting)))

如果是函数,所有index*符号,加上viewgreeting必须被引用:GET

; Routing
(defroutes main-routes
  (GET "/"    [] '(index))
  (GET "/en/" [] '(index))
  (GET "/fr/" [] '(index-fr))
  (GET "/:greeting/" '[greeting] '(view greeting)))

由于函数参数是在调用函数之前评估的,因此一旦读取表单,就会评估(index) et al 。此外,greetingarg 将在每个 HTTP 请求上发生变化,因此显然无法提前知道。

该宏还负责处理常规函数(通常)不可能的所有解构魔法。

经常令人困惑的事情(并且没有向初学者很好地解释)是这样的一行:

(GET "/:greeting/" [greeting] (view greeting))

不是正常的“Clojure 代码”。相反,它是一种速记(准确地说是域特定语言或 DSL),GET宏将摄取并用作如何生成“合法”Clojure 代码的指令。DSL 通常比最终生成的代码更短、更简单、更方便人类,就像 Clojure 比 Clojure 编译器生成的 Java 字节码或最终的机器汇编语言代码更短、更简单、更方便由 JVM 生成。

简而言之,每个宏都是一个“预编译器”,它将 DSL 转换为普通的 Clojure,然后由 Clojure 编译器摄取以生成 Java 字节码。

话虽如此,可以重新安排将所有宏魔术放入defroutes宏中,以便GET符号既不是函数也不是宏,而只是一种标记,如:get实现中的关键字。作为用户,这些实现细节通常并不重要。

更新

最好仅在函数不起作用或非常尴尬时使用宏。决定因素通常是是否要使用裸(未引用)符号,但不提前评估它们。Core Clojure 本身将宏用于许多其他语言中的“内置”构造,包括defnforandorwhen等。

另请注意,宏不能做函数可以做的某些事情,例如作为高阶函数的参数,如filter.

总之,一个函数定义了一个行为。宏定义语言扩展

于 2017-06-21T19:10:39.257 回答