请在2024年Clojure调查中分享您的想法!

欢迎!请查看关于页面以了解更多此平台的工作方式。

+5投票
集合

我建议添加:rest键用于地图解构语法。
您认为这一功能会有哪些用途呢?

(let [m {:a 1 :b 2}
      {:keys [a] :rest r} m]
  (assert (= {:b 2} r)))
      

或者像数组的其余部分一样 [a b & r]

(let [m {:a 1 :b 2}
      {:keys [a]
       :& r} m]
  (assert (= {:b 2} r)))

2个回答

+2投票

被选中
 
最佳答案

这通常没有意义,因为地图是无序的(默认情况下),按照这种方式解构并不能保证你首先得到[:a 1]这个键值对。

现在虽然您可以像处理一个键值对序列(虽然键值对的顺序是随机的)那样使用序列解构,然后对第一个键值对使用关联解构

(let [m {:a 1 :b 2}
      [[& {:keys [a b]}] & r] m]
  (println a b r))
;; 1 nil ([:b 2])

但再次强调,这里没有保证[:a 1]会被首先看到,您也可能得到[:b 2]。

你没有正确理解我的意思。
我只是写下 `[a b & r]` 来建议使用 `:&` 关键字,而不是 `:rest`。

问题是关于获取没有指定键的映射。
映射的顺序并不重要。

请看这个例子:(assert (= {:b 2} r))。它使用的是花括号,而不是方括号。
好的,我以为我们不会这样做。
只是出于好奇,有什么理由不做呢?我遇到过一些地方,在这种情况下,不想以后反复使用同样的键,会比较方便。
0 投票

如果你想自己实现,可以在自己的库中使用宏来扩展语言。这是一种有限的方法,尽管它不会递归遍历形式并且完整地替换 let;如果你想要启用 :rest 表单,你将不得不用它代替 let。有使用宏工具(如 macrolet 和其他工具)进行代码遍历和扩展的方法,但这需要读者自己练习。质量保证告知我,他们没有时间来测试除了所见直接的 repl 输出之外的内容,所以请注意用户风险。

(defmacro fancy-let [bindings & body]
  (let [binds (partition-all 2 bindings)
        _     (assert (every? #(= 2 (count %)) binds) "binding form must be even yo!")]
    `(let [~@(->> (for [[l r :as b] binds]
                    (if (and (map? l)
                             (l :rest)
                             (or (l :keys) (l :syms) (l :strs)))
                      (let [ks        (l :keys)
                            strs      (l :strs)
                            syms      (l :syms)
                            remaining (l :rest)
                            selected  (concat (map keyword ks)
                                              (map name strs)
                                              (for [s syms]
                                                `(quote ~s)))
                            symb      (gensym "the-map")]
                        [symb r
                         (dissoc l :rest)  symb
                         remaining        `(dissoc ~symb ~@selected)])
                      b))
                  (reduce (fn [acc xs] (apply conj acc xs)) []))]
       ~@body)))
user> (fancy-let [{:keys [a] :strs [name age] :syms [origin] :rest m}
                 {:a 1 :b 2 :c 3 "name" "bilbo" "age" 200 'origin :shire}]
                 {:a a :name name :age age :origin origin :remaining m})
{:a 1, :name "bilbo", :age 200, :origin :shire, :remaining {:b 2, :c 3}}
欢迎来到 Clojure 问答社区,您可以在这里提出问题,并从 Clojure 社区的成员那里获得答案。
...