If statement 如果让clojure进来,更好的筑巢方式
假设我有此表单的地图:If statement 如果让clojure进来,更好的筑巢方式,if-statement,clojure,If Statement,Clojure,假设我有此表单的地图: (def m {:a "A" :b "B"}) 如果:a和:b都不是零,我想做点什么,我可以做: (if-let [a (:a m)] (if-let [b (:b m)] ... etc )) 或 甚至 (if (every? m [:a :b]) (let [{a :a b :b} m] ... etc )) 有没有更简洁(即一行)的方法来实现这一点?没有?是一个很好的快捷方式: user> (not-any? nil? [
(def m {:a "A" :b "B"})
如果:a
和:b
都不是零,我想做点什么,我可以做:
(if-let [a (:a m)]
(if-let [b (:b m)]
... etc ))
或
甚至
(if (every? m [:a :b])
(let [{a :a b :b} m]
... etc ))
有没有更简洁(即一行)的方法来实现这一点?
没有?
是一个很好的快捷方式:
user> (not-any? nil? [(m :a) (m :b)])
true
user> (not-any? nil? [(m :a) (m :b) (m :d)])
false
user>
您可以使用——Clojure的一个有用特性。这还利用了和
短路的事实,并且在第二个映射中未找到的第一个映射中的任何键都会得到nil
,一个错误值:
(let [{a :a b :b} {:a 1 :b "blah"}]
(and a b (op a b)))
好的,这是两行而不是一行。。。。此外,这并不区分
nil
和其他错误值。我不太确定如果键具有非nil值,或者是否希望返回非nil键或值,您要做什么。所以,我刚刚解决了返回非零密钥的问题
您可以使用以下步骤作为最终解决方案的中间步骤
我展示了我使用的所有步骤,不是为了学究,而是为了提供一个完整的答案。名称空间是repl test
。它有一个与之关联的main
repl-test.core=> (def m {:a "A" :b "B" :c nil})
#'repl-test.core/m
repl-test.core=> (keys m)
(:a :c :b)
最后:
; Check key's value to determine what is filtered through.
repl-test.core=> (filter #(if-not (nil? (%1 m)) (%1 m)) (keys m) )
(:a :b)
我认为这里可能需要一个宏来创建您想要的行为。我从未写过一本(至今),但下面的陈述向我表明,这可能相当简单:
(let [{:keys [a b]} m]
(when (every? identity [a b])
(println (str "Processing " a " and " b))))
使用解构绑定的:keys
形式和every?
可以对密钥向量的单个规范进行解构和检查,并且绑定的局部变量在以下代码块中可用
这可用于生成宏,例如(当每个?[keys coll]代码都带有绑定时)
如果我能花点时间找出如何做,我可能会用宏代码更新这个答案。顺便说一句,我发现了一个难看的单行线,因为
和
返回其参数列表中的最后一项,如果它们都是真的:
(if-let [[a b] (and (:a m) (:b m) [(:a m)(:b m)])]
(println "neither " a " nor " b " is falsey")
(println "at least one of " a " or " b " is falsey"))
(每个?一些?…)
不是更好吗?这样你就可以避免双重否定不是吗?当发现一个问题时,可以停止检查,在许多情况下,时间会略有改善
(if-let [[a b] (and (:a m) (:b m) [(:a m)(:b m)])]
(println "neither " a " nor " b " is falsey")
(println "at least one of " a " or " b " is falsey"))