Clojure解构中的:or是什么意思?

6

faraday的scan函数源代码(https://github.com/ptaoussanis/faraday/blob/master/src/taoensso/faraday.clj#L1197)有一个解构形式,我很难理解...

(source far/scan)
(defn scan
  "..."
  [client-opts table
   & [{:keys [attr-conds last-prim-kvs span-reqs return limit total-segments
              filter-expr
              segment return-cc?] :as opts
       :or   {span-reqs {:max 5}}}]]
...)

那个:or {span-reqs {:max 5}}是什么意思?
3个回答

10

这是默认值。欲知详情,请参见http://clojure.org/guides/destructuring

(def my-map {:a "A" :b "B" :c 3 :d 4})
(let [{a :a, x :x, :or {x "Not found!"}, :as all} my-map]
  (println "I got" a "from" all)
  (println "Where is x?" x))
;= I got A from {:a "A" :b "B" :c 3 :d 4}
;= Where is x? Not found!

使用:keys,我们可以得到

(let [{:keys [a x] :or {x "Not found!"}, :as all} my-map]
  (println "I got" a "from" all)
  (println "Where is x?" x))

得到相同的结果


6

:or {span-reqs {:max 5}}指定如果opts没有键:span-reqs,那么span-reqs将被绑定到映射{:max 5}

请注意,span-reqs并不直接引用键:span-reqs - 这也是可能的:

(defn scan
  [client-opts table
   & [{:keys [attr-conds last-prim-kvs return limit total-segments
              filter-expr
              segment return-cc?] :as opts
       foo :span-reqs
       :or {foo {:max 5}}}]])

请注意,在:or映射中,您通常可以为在解构形式中绑定的符号提供默认表达式。
注:在:or中放置运行时表达式要小心。从Clojure 1.9-alpha14开始,它们仍将被评估,无论它们是否需要(请参见http://dev.clojure.org/jira/browse/CLJ-1676)。

2
为了更好地理解,我将用一个示例函数来说明:

将其放入上下文中:

user> (defn foo [client-opts
                 table
                 & [{:keys [attr-conds
                            last-prim-kvs
                            span-reqs
                            return
                            limit
                            total-segments
                            filter-expr
                            segment return-cc?]
                     :as opts
                     :or {span-reqs {:max 5}}}]]
        (println "client-opts")
        (clojure.pprint/pprint client-opts)
        (println "table")
        (clojure.pprint/pprint table)
        (println "opts")
        (clojure.pprint/pprint opts)
        (println "the symbol attr-conds is bound to:" attr-conds)
        (println "the symbol limit is bound to:" limit)
        (println "the symbol span-reqs is bound to:" span-reqs))
#'user/foo
user> (foo :I'm-a-client-opt
           :I'm-a-table           
           {:attr-conds 1
            :span-reqs [1 2 3]
            :limit 47}
           {:attr-conds :i-will-be-ignored}
           {:limit :i-will-also-be-ignored})
client-opts
:I'm-a-client-opt
table
:I'm-a-table
opts
{:attr-conds 1, :span-reqs [1 2 3], :limit 47}
the symbol attr-conds is bound to: 1
the symbol limit is bound to: 47
the symbol span-reqs is bound to: [1 2 3]
nil

现在我们看到它将一些名称绑定到列表中第一个映射的部分,因此让我们拆开这个解构表达式:

& ;; this symbol collects all the rest of the arguments into a list
[ ;; this one then does list destructuring on the list indicated by the &
 {:keys [attr-conds     ;; This block destructures the first (and only the first) entry in the vector.
         last-prim-kvs  ;; Because this is a map it will do map destructuring and 
         span-reqs      ;; bind (assigns) values to symbols in this list
         return
         limit
         total-segments
         filter-expr
         segment return-cc?]
  :as opts              ;; the entire map in the first position in the list created by the & will be bound to the name opts
  :or {span-reqs {:max 5}}}] ;; if span-reqs is not in the map at all, 
                             ;; then the map {:max 5} will be bound to the name 
                             ;; span-reqs instead

因此,在嵌套的解构表达式中,关键字“:or”为符号分配默认值,如果函数的第三个参数是一个映射,并且该映射没有为关键字“:span-reqs”提供值。如果关键字“:span-reqs”存在并包含不提供“:max”值的其他键,则不执行任何操作。在此上下文中,“:or”不会将默认值合并到映射中,仅在完全缺少值时提供值:

以下是完全未指定值的情况:

user> (foo :I'm-a-client-opt
           :I'm-a-table           
           {:attr-conds 1
            ;; :span-reqs [1 2 3] ;; removed this one
            :limit 47}
           {:attr-conds :i-will-be-ignored}
           {:limit :i-will-also-be-ignored})
client-opts
:I'm-a-client-opt
table
:I'm-a-table
opts
{:attr-conds 1, :limit 47}
the symbol attr-conds is bound to: 1
the symbol limit is bound to: 47
the symbol span-reqs is bound to: {:max 5}
nil

同时,如果指定的值不包括:max,则再次使用一个值。

user> (foo :I'm-a-client-opt
           :I'm-a-table           
           {:attr-conds 1
            :span-reqs {:min -7} ;; present but contains something else
            :limit 47}
           {:attr-conds :i-will-be-ignored}
           {:limit :i-will-also-be-ignored})
client-opts
:I'm-a-client-opt
table
:I'm-a-table
opts
{:attr-conds 1, :span-reqs {:min -7}, :limit 47}
the symbol attr-conds is bound to: 1
the symbol limit is bound to: 47
the symbol span-reqs is bound to: {:min -7}
nil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接