3

我一直在研究 if-let 和 when-let 宏,我无法确定它们究竟“做什么”。特别是,文档说:

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)“测试”指的是什么?

4

3 回答 3

4

直接回答您的问题:

  1. =>表示“扩展到”,如 BNF 表示法。在这种情况下,这意味着您需要两种形式:绑定形式和测试。
  2. “测试”是指任何可以评估为布尔值的东西。

顺便说一句,我认为这里的文档不清楚甚至可能是错误的。很难(或不可能)推断出构成绑定的两种形式需要包含在一个向量中。恕我直言,它应该是when-let ([[bindings] & body])(在 args 中显示的bindings => [binding-form test]向量)或(在类似 BNF 的扩展中显示的向量。)

于 2012-04-06T07:00:06.940 回答
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 ' 分支。”

wrt 文档约定

bindings => binding-form test
  1. =>读起来像'相当于'
  2. test是某种返回值的形式

对于这些功能中的大多数,clojuredocs是您的朋友,示例用法通常可以说明问题。如果 clojuredocs 示例不适合您,您可以添加自己的

于 2012-04-06T07:19:38.703 回答
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,在 thatx中将绑定到 的返回值(a-function)。这个函数可以返回nilfalse。在这种情况下,隐式测试失败(do-something-else)并将被评估。如果xis notnil和 not 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-letwhen-let更清晰。

于 2012-04-06T03:04:04.357 回答