15

我有一个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作为值,在这种情况下总是使用默认值。

4

2 回答 2

25

(or (:key hash) default)和之间的一个关键区别(:key hash default)是前者default仅在必要时进行评估。在后一种情况下,它总是被评估。or因此,如果评估default成本高昂,您应该使用。

当您的哈希包含在布尔上下文中为假的值时,另一个区别变得明显。在这种情况下,(or (:key hash) default)将评估这些值而default不是您期望的值。与表达式相反,将产生正确的结果。作为旁注,在将值存储为散列之前请三思而后行。falsenilor(: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 习语的人可能更容易解析第一个表达式。

于 2012-12-11T09:43:19.747 回答
1

这就是: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
于 2019-10-05T13:19:53.093 回答