有没有办法可以重用 EDN 中已定义键的值?
Is there a way we can re-use value of defined keys in EDN?
有没有办法可以重用 EDN 中定义的键值?
例如:
如果我关注 EDN
{
:abc "value1"
:def :abc
}
当我在 Clojure 中阅读上面的 EDN 时,我想要传递 'def' 键值 1,即 :abc 的值。但目前 :abc 字符串在我使用 EDN 读取字符串函数
读取时被传递
普通的 EDN 中没有这样的东西。但是您可以构建一个两阶段传递,或者首先在 EDN 字符串本身上替换内容,或者在通过操纵数据结构解析 EDN 之后更好地执行此操作,例如:
(require '[clojure.edn :as edn])
(require '[clojure.walk :as walk])
(defrecord self [key])
(defn tag-self
[v]
(->self v))
(defn custom-readers []
{'x/self tag-self})
(defn replace-self
[coll]
(walk/prewalk
(fn [form]
(if (map? form)
(reduce-kv
(fn [acc k v]
(assoc acc k (if (= self (type v))
(get form (:key v))
v)))
{}
form)
form))
coll))
(replace-self
(edn/read-string
{:readers (custom-readers)}
"[{:abc \"value1\"
:def #x/self :abc}
{:abc {:bbb \"value2\"
:def #x/self :bbb}
:def #x/self :abc
:xyz {:aaa \"value3\"
:nope #x/self :abc
:def #x/self :aaa}}]"))
会 return:
[{:abc "value1", :def "value1"}
{:abc {:bbb "value2", :def "value2"},
:def {:bbb "value2", :def "value2"},
:xyz {:aaa "value3", :nope nil, :def "value3"}}]
诀窍是我使用我创建的 #x/self
标记 reader 标记对当前映射的另一个键的引用,这会将值包装在 self
记录中.现在我们只遍历 returned 数据结构,每次遇到 self
类型时,我们将其替换为同一映射中其 :key
属性的值。
上面的 replace-self
walker 是递归的,所以你可以看到它可以处理嵌套的地图,它甚至可以替换地图内部的 self
引用,这些引用本身是 self
引用的。不过它只做局部作用域,所以 :nope #x/self :abc
没有被父映射中的 :abc
的值替换,并且由于在它自己的映射中没有 :abc
键,它的值被设置为 nil
.
自定义标签是可选的,我这样做是因为现在它适用于任何类型的密钥。但是如果你希望这是他们的行为,你也可以在 replace-self 中使用 keyword?
代替:
(defn replace-self
[coll]
(walk/prewalk
(fn [form]
(if (map? form)
(reduce-kv
(fn [acc k v]
(assoc acc k (if (keyword? v)
(v form)
v)))
{}
form)
form))
coll))
(replace-self
(edn/read-string
"[{:abc \"value1\"
:def :abc}
{:abc {:bbb \"value2\"
:def :bbb}
:def :abc
:xyz {:aaa \"value3\"
:nope :abc
:def :aaa}}]"))
这将return和以前一样,只是不需要自定义标签和自我记录:
[{:abc "value1", :def "value1"}
{:abc {:bbb "value2", :def "value2"},
:def {:bbb "value2", :def "value2"},
:xyz {:aaa "value3", :nope nil, :def "value3"}}]
有没有办法可以重用 EDN 中定义的键值?
例如: 如果我关注 EDN
{
:abc "value1"
:def :abc
}
当我在 Clojure 中阅读上面的 EDN 时,我想要传递 'def' 键值 1,即 :abc 的值。但目前 :abc 字符串在我使用 EDN 读取字符串函数
读取时被传递普通的 EDN 中没有这样的东西。但是您可以构建一个两阶段传递,或者首先在 EDN 字符串本身上替换内容,或者在通过操纵数据结构解析 EDN 之后更好地执行此操作,例如:
(require '[clojure.edn :as edn])
(require '[clojure.walk :as walk])
(defrecord self [key])
(defn tag-self
[v]
(->self v))
(defn custom-readers []
{'x/self tag-self})
(defn replace-self
[coll]
(walk/prewalk
(fn [form]
(if (map? form)
(reduce-kv
(fn [acc k v]
(assoc acc k (if (= self (type v))
(get form (:key v))
v)))
{}
form)
form))
coll))
(replace-self
(edn/read-string
{:readers (custom-readers)}
"[{:abc \"value1\"
:def #x/self :abc}
{:abc {:bbb \"value2\"
:def #x/self :bbb}
:def #x/self :abc
:xyz {:aaa \"value3\"
:nope #x/self :abc
:def #x/self :aaa}}]"))
会 return:
[{:abc "value1", :def "value1"}
{:abc {:bbb "value2", :def "value2"},
:def {:bbb "value2", :def "value2"},
:xyz {:aaa "value3", :nope nil, :def "value3"}}]
诀窍是我使用我创建的 #x/self
标记 reader 标记对当前映射的另一个键的引用,这会将值包装在 self
记录中.现在我们只遍历 returned 数据结构,每次遇到 self
类型时,我们将其替换为同一映射中其 :key
属性的值。
上面的 replace-self
walker 是递归的,所以你可以看到它可以处理嵌套的地图,它甚至可以替换地图内部的 self
引用,这些引用本身是 self
引用的。不过它只做局部作用域,所以 :nope #x/self :abc
没有被父映射中的 :abc
的值替换,并且由于在它自己的映射中没有 :abc
键,它的值被设置为 nil
.
自定义标签是可选的,我这样做是因为现在它适用于任何类型的密钥。但是如果你希望这是他们的行为,你也可以在 replace-self 中使用 keyword?
代替:
(defn replace-self
[coll]
(walk/prewalk
(fn [form]
(if (map? form)
(reduce-kv
(fn [acc k v]
(assoc acc k (if (keyword? v)
(v form)
v)))
{}
form)
form))
coll))
(replace-self
(edn/read-string
"[{:abc \"value1\"
:def :abc}
{:abc {:bbb \"value2\"
:def :bbb}
:def :abc
:xyz {:aaa \"value3\"
:nope :abc
:def :aaa}}]"))
这将return和以前一样,只是不需要自定义标签和自我记录:
[{:abc "value1", :def "value1"}
{:abc {:bbb "value2", :def "value2"},
:def {:bbb "value2", :def "value2"},
:xyz {:aaa "value3", :nope nil, :def "value3"}}]