我一直在关注if-let和when-let宏,我无法确定它们“做”到底是什么。特别是文档sais:
clojure.core/when-let
([bindings & body])
Macro
bindings => binding-form test
When test is true, evaluates body with binding-form bound to the value of test
因此我对宏的记录方式感到有些困惑。
1)“=>”是什么象征意味着?
2)“测试”指的是什么?
答案 0 :(得分:4)
直接回答您的问题:
=>
表示“扩展为”,如BNF表示法。在这种情况下,它意味着您需要两种形式:绑定表单和测试。顺便说一下,我认为这里的文档不清楚甚至可能是错误的。很难(或不可能)推断构成绑定的两种形式需要被包含在向量中。恕我直言,它应该是when-let ([[bindings] & body])
(args中显示的向量)或bindings => [binding-form test]
(BNF类扩展中显示的向量)。
答案 1 :(得分:4)
在处理宏来调用macroexpand
并查看生成的代码是什么时,这通常很有用。
(macroexpand
'(if-let [x (myfunc)]
(foo x)
(bar))
; expands to
(let* [temp__3695__auto__ (myfunc)]
(if temp__3695__auto__ (clojure.core/let [x temp__3695__auto__]
(foo x))
(bar)))
; the generated symbols are necessary to avoid symbol
; capture but can confuse. The above is equivalent to:
(let* [ t (myfunc)]
(if t
(let [x t]
(foo x))
(bar))
因此,您可以看到if-let
是“将局部变量绑定到函数调用结果的简写,如果该变量是真实的,则调用第一个表单,否则调用另一个表单。您返回的值功能仅适用于'truthy'分支。“
文件惯例
bindings => binding-form test
=>
读取的内容类似于'等同于'test
是一种返回值的表单对于大多数这些功能,clojuredocs是您的朋友,示例用法通常会澄清事情。如果clojuredocs示例没有为您剪切,您可以添加自己的
答案 2 :(得分:2)
请考虑以下代码:
(if-let [x (a-function)]
(do-something-with x) ;; (a-function) returned a truthy result
(do-something-else) ;; (a-function) returned nil or false
这与let
类似,因为x
将绑定到(a-function)
的返回值。此函数可以返回nil
或false
。在这种情况下,隐式测试失败,将评估(do-something-else)
。如果x
不是nil
而不是false
,则会评估(do-something-with x)
。
这可能有用的场景:
(if-let [user (find-logged-in-user)]
(do something with logged in user) ;; a user was found
(redirect to login page) ;; no user was found
我有时使用类似下面的内容,有条件地将键添加到选项地图中:
(apply merge {:username "joe"
:email "joe@example.com"}
(when-let [name (find-full-name)] {:name name})
(when-let [dob (find-date-of-birth)] {:dob dob}))
这会生成包含:username
和:email
键的地图,如果找到用户的全名则会生成:name
键,如果是日期则会生成:dob
键出生了。
我希望这会使if-let
和when-let
的使用更加清晰。