我有一张名为机器人
的 map 。在查找 map 时,如果给定键的机器人不存在,我想创建一个。 clojure.core/get
与 not-found
arg 似乎正是我所需要的。
但是,似乎 not-found
表达式是急切求值的。如何防止这种评估,以便仅在机器人不存在时才创建一个新机器人?
robot> (def robots {1 {:name "R2D2"}})
#'robot/robots
robot> (get robots 1)
{:name "R2D2"}
robot> (get robots 1 (println "damn it"))
damn it
{:name "R2D2"}
最佳答案
问题是这不是一个分支语句——它实际上需要在 not-found
槽中得到一个值,而不是一个形式或函数。所以你可以使用分支语句:
(if-let [r (get robots 1)] r (println "Beep boop"))
如果打字太多,你可以考虑一下:
(defmacro get-lazy
[map idx statement]
`(if-let [v# (get ~map ~idx)] v# ~statement))
user=> (get-lazy robots 1 (println "Oops!"))
{:name "R2D2"}
根据 A.Webb 的评论提示,我们得出以下宏。它使用与上面相同的方法,并且还可以处理包含 false
和 nil
值的映射。它也比在 map 上调用 contains?
和 get
更快。不要使用错误的返回值 (false/nil) 来提示您该项目不存在,而是使用 get
的内置功能并检查“中永远不会出现的内容”狂野” map 。
(defmacro get-lazy
[map idx statement]
`(let [r# (get ~map ~idx ~::nil)]
(if (identical? r# ~::nil) ~statement r#)))
user=> (get-lazy {:idx 8} :idx (println "Yo."))
8
user=> (get-lazy {:coconuts :migration} :swallow (println "Who goes there?"))
Who goes there?
user=> (ns another.ns)
another.ns=> (user/get-lazy {:LUE ::nil} :LUE (println "42."))
:another.ns/nil
您可以避开宏并走功能路线:
(let [sentinel ::nil]
(defn lazyget
[map idx function]
(let [r (get map idx sentinel)]
(if (identical? r sentinel) (function) r))))
这在我的机器上有点慢。
关于Clojure:如何避免对 map 获取中未找到的表达式进行评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23197520/