【问题标题】:What does :or mean in Clojure destructuring?: 或在 Clojure 解构中是什么意思?
【发布时间】:2016-12-09 06:35:11
【问题描述】:

法拉第扫描功能的来源 (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}} 是做什么的?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    这是默认值。更多详情请见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))
    

    结果相同

    【讨论】:

      【解决方案2】:

      :or {span-reqs {:max 5}} 指定如果 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 映射中,您通常可以为您在解构形式中绑定的符号提供默认表达式。

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

      【讨论】:

        【解决方案3】:

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

        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 提供值的映射,则该嵌套解构表达式中的关键字 :or 会为符号分配默认值。如果关键字 :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
        

        【讨论】:

          猜你喜欢
          • 2014-08-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-05
          相关资源
          最近更新 更多