在 Clojure 中,如何解构映射的所有键?

发布于 2025-01-07 02:52:50 字数 347 浏览 1 评论 0原文

在 clojure 中,可以像这样解构映射的某些键:

(let [{:keys [cpp js]} {:cpp 88 :js 90}] 
   (println js); 90
   (println cpp); 88
 )

Is there a way to destruct all the key of a map?

也许是这样的:

(let [{:all-the-keys} {:cpp 88 :js 90}] 
   (println js); 90
   (println cpp); 88
 )

In clojure, it is possible to destructure some keys of a map like this:

(let [{:keys [cpp js]} {:cpp 88 :js 90}] 
   (println js); 90
   (println cpp); 88
 )

Is there a way to destructure all the keys of a map?

Maybe something like:

(let [{:all-the-keys} {:cpp 88 :js 90}] 
   (println js); 90
   (println cpp); 88
 )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

美人骨 2025-01-14 02:52:50

事实并非如此,而且这也不是一个好主意。想象一下:

(let [{:all-the-keys} m]
  (foo bar))

foo 和 bar 是全局变量吗?当地人?您应该从 m 中提取密钥吗?如果 m 有时 包含 foo 键,并且 foo 也是一个全局函数,那么这段代码应该做什么?有时调用全局,有时调用m中存储的函数?

忽略技术问题(可以克服),这对于可读性和可预测性来说确实是一场灾难。只需明确您想要拔出哪些钥匙即可;如果您经常想要取出相同的十个键,您可以编写一个简单的宏,例如 (with-person p body) 来简化您的常见情况。

Not really, and it wouldn't be a good idea. Imagine:

(let [{:all-the-keys} m]
  (foo bar))

Are foo and bar globals? Locals? Keys you should extract from m? What should this code do if m sometimes contains a foo key, and foo is also a global function? Sometimes you call the global, and sometimes you call the function stored in m?

Ignoring the technical problems (which could be overcome), it is really a disaster for readability and predictability. Just be explicit about what keys you want to pull out; if you frequently want to pull out the same ten keys, you can write a simple macro like (with-person p body) that simplifies that common case for you.

小霸王臭丫头 2025-01-14 02:52:50

这个问题已经很老了,所以你可能已经忘记了,但是当我尝试做同样的事情时,它出现在谷歌上,所以如果我发布我的解决方案,它可能会帮助其他人。

(defmacro let-map [vars & forms]
  `(eval (list 'let (->> ~vars keys
                         (map (fn [sym#] [(-> sym# name symbol) (~vars sym#)]))
                         (apply concat) vec)
               '~(conj forms 'do))))

这基本上将映射 {:cpp 88 :js 90} 转换为绑定形式 [cpp 88 js 90] 然后构造一个 let 绑定,并执行一些 eval-jitsu 以确保这种情况在运行时发生。

(def test-map {:cpp 88 :js 90})
(let-map test-map
  (println js)
  (println cpp))
;=> 90
;=> 88

This question is pretty old so you've probably forgotten about it, but it came up on google when I was trying to do the same thing, so if I post my solution it might help someone else out.

(defmacro let-map [vars & forms]
  `(eval (list 'let (->> ~vars keys
                         (map (fn [sym#] [(-> sym# name symbol) (~vars sym#)]))
                         (apply concat) vec)
               '~(conj forms 'do))))

This basically transforms the map {:cpp 88 :js 90} into the binding form [cpp 88 js 90] then constructs a let binding, along with performing some eval-jitsu to make sure that this happens at run time.

(def test-map {:cpp 88 :js 90})
(let-map test-map
  (println js)
  (println cpp))
;=> 90
;=> 88
池予 2025-01-14 02:52:50

您可以编写一个宏来执行此操作(有效地创建迷你 DSL),但我认为这不是一个好主意,原因如下:

  • 为了创建正确的编译时文字 js 和 cpp,您需要需要在编译时解构映射。这对于你可以用它做的事情来说是相当有限的(例如,你必须提前指定键,并且它不能在高阶函数中使用)
  • 当更简单的方法需要使用宏时,宏通常是一个坏主意完成这项工作(见下文)

我建议在您的情况下使用简单的 doseq循环地图:

(let [my-map {:cpp 88 :js 90}]
  (doseq [[k v] my-map]
    (println v)))

请注意:

  • 每个地图条目中提取键 k 和值 v
  • 您可以使用上面的解构从我使用的 doseq 而不是 for 因为它是非惰性的,并且在这个示例中您似乎仅将循环用于 println 副作用。
  • 相反,如果您想要一个惰性值序列(88 90),那么 for 会比较合适。

You could write a macro to do this (effectively creating a mini-DSL), but I don't think it is a very good idea for the following reasons:

  • In order to create the right compile-time literals js and cpp, you would need to destructure the map at compile time. This would be quite limiting in terms of what you could do with it (you would have to specify the keys in advance, and it couldn't use in higher order functions, for example)
  • Macros are generally a bad idea when a simpler method would do the job (see below)

I'd recommend just using a simple doseq in your case to loop over the map:

(let [my-map {:cpp 88 :js 90}]
  (doseq [[k v] my-map]
    (println v)))

Note that:

  • You can use destructuring as above to extract both the key k and value v from each map entry
  • I used doseq rather than for because it is non-lazy and it seems in this example that you are using the loop only for the println side effects.
  • If instead you want a lazy sequence of values (88 90) then for would be appropriate.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文