法拉第扫描函数(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}}
做了什么?
答案 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-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 :(得分: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