clojure地图中的默认值

时间:2012-12-11 09:29:36

标签: map clojure

我有一张clojure地图。将其命名为opts。我知道从这个地图获取值的两种方法,这样如果没有键获得一些默认值:

(let [opts {}
      title-1 (or (:title opts) "Default title")
      title-2 (:title opts "Default title")]
  (println title-1 title-2))

我看到一些库(quil,incanter)使用or的第一种方法。在我看来,第二种方法更简洁,更清洁。第一种方法有优势吗?
使用(or (:title opts) "Default value")的缺点是我们无法再将falsenil作为值传递,在这种情况下始终使用默认值。

2 个答案:

答案 0 :(得分:22)

(or (:key hash) default)(:key hash default)之间的关键区别在于前者仅在必要时评估default。在后一种情况下,它总是被评估。因此,如果or的评估费用很高,则应使用default

当您的哈希包含布尔上下文中的false值时,另一个区别变得明显。如果此类值(or (:key hash) default)将评估为default,而不是您期望的falsenil。与or表达式相反,(:key hash default)将产生正确的结果。作为旁注,在将nil作为值存储在散列中之前,请三思而后行。

很好,那些是重要的区别。现在让我们转向次要的。

(or (:title opts) "Default title")

由读者扩展为

;; Redacted for the sake of brevity.
(let* [x (:title opts)]
  (if x
    x
    "Default title"))

可以说,它比简单评估

效率低
(:title opts "Default title")

当然没有任何基准,很难估计差异是速度,但我认为它应该是边缘的。

另一方面,对于不习惯(or (:key hash) :default)成语的人来说,乍一看(:key hash :default)似乎更容易理解。考虑来自其他语言的程序员。例如,在Ruby中,处理散列的非存在元素的典型方法是

val = hash[:key] || :default

因此,第一个表达可能更容易被不习惯某些Clojure习语的人解析。

答案 1 :(得分:0)

这是地图解构时使用的:or键。

(defn f [{:keys [title-1 title-2] :as opts
          :or {title-1 "default-1" title-2 "default-2"}}]
  (println opts)
  (println title-1)
  (println title-2))

给你

> (f {})
{}
default-1
default-2
nil

> (f {:title-1 "foo"})
{:title-1 foo}
foo
default-2
nil

> (f {:title-2 "bar"})
{:title-2 bar}
default-1
bar
nil

> (f {:title-1 "foo" :title-2 "bar"})
{:title-1 foo, :title-2 bar}
foo
bar
nil