【问题标题】:Is there a way we can re-use value of defined keys in EDN?有没有一种方法可以重用 EDN 中已定义键的值?
【发布时间】:2019-11-30 08:44:49
【问题描述】:

有没有一种方法可以重用 EDN 中定义的键值?

例如: 如果我有以下 EDN

{
   :abc "value1"
   :def :abc
}

当我在 Clojure 中阅读上面的 EDN 时,我想要传递 'def' 键 value1,它是 :abc 的值。但是目前 :abc 字符串在我使用 EDN 读取字符串函数读取它时被传递

【问题讨论】:

  • 不,你必须自己实现它。 Fern 是一种支持类似这样的 edn 格式。

标签: clojure edn


【解决方案1】:

在普通的 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}}]"))

将返回:

[{:abc "value1", :def "value1"}
 {:abc {:bbb "value2", :def "value2"},
  :def {:bbb "value2", :def "value2"},
  :xyz {:aaa "value3", :nope nil, :def "value3"}}]

诀窍是我使用我创建的#x/self 标签阅读器标记对当前映射的另一个键的引用,它将值包装在self 记录中。现在我们只需遍历返回的数据结构,每次遇到self 类型时,我们都会将其替换为同一映射中:key 属性的值。

上面的replace-self walker 是递归的,所以你可以看到它可以处理嵌套的maps,它甚至可以替换map 中的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}}]"))

这将返回和以前一样,只是不需要自定义标签和自我记录:

[{:abc "value1", :def "value1"}
 {:abc {:bbb "value2", :def "value2"},
  :def {:bbb "value2", :def "value2"},
  :xyz {:aaa "value3", :nope nil, :def "value3"}}]

【讨论】:

  • 在 EDN 字符串本身中执行此操作似乎需要大量工作才能获得非常脆弱的结果。当您已经提供了更高质量的解决方案时,我什至不会在答案中提及它。
猜你喜欢
  • 1970-01-01
  • 2014-06-23
  • 2014-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-14
  • 2021-10-10
相关资源
最近更新 更多