Clojure中嵌套Map的惯用方式是什么?

4

阅读Clojure代码时,我看到有两种不同的方式来构建Map:

;; 1.
(def event {:type :created :data {:start 1}})
;; 2.
(def event {:event/type :created :data/start 1})

甚至自Clojure 1.9以来,有对Map namespace syntax的支持,使得选择2非常简单易用。

我的问题是每种用法的理由(利弊),是否存在任何讨论/文章解释在Clojure中如何构建映射的深层思想?


1
第二个不是嵌套映射,而是一个扁平的单层映射,具有命名空间键。这与您指向的链接不同,该链接实际上是一个嵌套映射,内部嵌套层具有命名空间键。 - Charles Duffy
1
无论如何,每个都有独特而有价值的用例;我不会说其中任何一个在另一个方面不是惯用的。(例如:实际嵌套允许您在树的一部分进行更改,而未修改的叶子保留其原始标识;如果您基于更新进行传播/重新计算,则可以成为重要的性能优化!) - Charles Duffy
1个回答

3
你好像混淆了嵌套地图(字面上的一个地图作为键的值)和命名空间键,后者仍然只是关键字,但具有某些魔力。命名空间键到值的映射仍然只是单级映射。
你可能想看一下官方命名空间关键字解构示例,以便了解它们通常使用的一种方式——线索都在名称中,因为它们似乎旨在将键分组成语义相关的组,无论这是否对应于代码中的实际命名空间,或者是您正在即兴发挥的完全短暂的东西,由您决定。
它们的一个非常棒的属性是能够为命名空间关键字设置别名-因此,如果需要命名空间,则本地别名可以引用相同的关键字-例如:
(ns foo.bar
  (:require [foo.baz :as baz]))

(prn ::baz/yours) ; equivalent to :foo.baz/yours
(prn ::mine) ; equivalent to :foo.bar/mine

(defn formatted-name [{:baz/keys [yours]}]
  (str "hi:" yours))

(prn (formatted-name {::baz/yours "clojurian!"}))
(prn (formatted-name {:foo.bar/yours "also"})) ; same arguments, but previous isn't hardcoded.

这绝对是您经常看到的东西,特别是在较大的代码库中,它有助于组织。

如果我理解正确,::baz/yours没有引用foo.baz命名空间中的任何内容,对吗?如果是这样,那么像::mine这样的东西主要用于避免在可能反弹到多个命名空间的映射中发生冲突,对吗? - David Smith
是的!它们只是固定的值,除了它们自己以外没有任何引用。我知道这似乎有点模糊,但如果你稍微看一下,它们就像具有特殊能力的字符串常量。 - danp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接