我有一张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")
的缺点是我们无法再将false
和nil
作为值传递,在这种情况下始终使用默认值。
答案 0 :(得分:22)
(or (:key hash) default)
和(:key hash default)
之间的关键区别在于前者仅在必要时评估default
。在后一种情况下,它总是被评估。因此,如果or
的评估费用很高,则应使用default
。
当您的哈希包含布尔上下文中的false值时,另一个区别变得明显。如果此类值(or (:key hash) default)
将评估为default
,而不是您期望的false
或nil
。与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