:keys 解构的逆过程:从序列构造映射

Inverse process of :keys destructuring: construct map from sequence

我用 Clojure 写的越多,我就越遇到以下这种模式:

(defn mapkeys [foo bar baz]
   {:foo foo, :bar bar, :baz baz})

在某种意义上,这看起来像是解构的逆过程

(let [{:keys [foo bar baz]}] ... )

会实现。

Clojure 中是否有一种“内置”方式来实现与上述类似的东西 mapkeys(将名称映射到关键字 => 值)- 可能是任意长度的列表名字?

没有内置这样的东西,因为它不需要。与相当复杂的解构不同,在 Clojure 中构建映射非常简单,因此普通库可以采用奇特的方式来实现。例如,我很久以前写过 flatland.useful.map/keyed,它反映了 map 解构的三种模式:

(let [transforms {:keys keyword
                  :strs str
                  :syms identity}]
  (defmacro keyed
      "Create a map in which, for each symbol S in vars, (keyword S) is a
  key mapping to the value of S in the current scope. If passed an optional
  :strs or :syms first argument, use strings or symbols as the keys instead."
    ([vars] `(keyed :keys ~vars))
    ([key-type vars]
       (let [transform (comp (partial list `quote)
                             (transforms key-type))]
         (into {} (map (juxt transform identity) vars))))))

但是如果你只关心关键字,而不需要文档字符串,它可能会更短:

(defmacro keyed [names]
  (into {}
        (for [n names]
          [(keyword n) n])))

我发现我经常想要从单个值构建映射或解构映射以检索单个值。在 Tupelo Library I have a handy pair of functions 中,我一直使用的目的是:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(dotest
  (let [m {:a 1 :b 2 :c 3}]
    (with-map-vals m [a b c]
      (spyx a)
      (spyx b)
      (spyx c)
      (spyx (vals->map a b c)))))

结果

; destructure a map into values
a => 1
b => 2
c => 3

; construct a map
(vals->map a b c) => {:a 1, :b 2, :c 3}

P.S。当然,我知道您可以使用 :keys 语法进行解构,但对我来说它似乎总是有点不直观。