什么:或者在Clojure解构中意味着什么?

时间:2016-12-08 20:48:40

标签: clojure

法拉第扫描函数(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 个答案:

答案 0 :(得分:4)

这是默认值。有关详细信息,请参阅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))

具有相同的结果

答案 1 :(得分:4)

:or {span-reqs {:max 5}}指定iff opts没有密钥:span-reqsspan-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地图中,您通常可以为在析构函数表单中绑定的符号提供默认表达式。

<磷>氮。 B。:将运行时表达式放在:or中时要小心。从Clojure 1.9-alpha14开始,无论是否需要,它们仍将被评估(见http://dev.clojure.org/jira/browse/CLJ-1676)。

答案 2 :(得分:1)

为了把它放在上下文中,我将它包装在一个示例函数中:

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

所以关键字:或者在嵌套的解构表达式中为符号赋予默认值,如果函数的第三个参数是不为关键字提供值的映射:span-reqs。如果关键字:span-reqs存在并且包含其他键而不提供以下值的值,则不执行任何操作:max。在此上下文中将默认值合并到地图中,如果它完全丢失,它只提供一个值:

这里是没有指定的值:

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