在Clojure中重载关键字

时间:2011-04-07 15:45:37

标签: clojure

我有这样的地图:

(def a {:a 1, :b 2})

:我希望重载地图,以便某些关键字执行以下功能:

(c: a)

可以执行一个功能。这可能吗?

更新

我意识到我可以做类似的事情:

(def a {:a (fn[] 1) :b (fn[] 2) :c (fn[] x)})

:和

((c: a))

:但是我必须将我拥有的每个现有地图条目转换为函数。

我希望每次都能重新评估该功能。例如,当我这样做时:

(def ab{:a 1         :b 2         :c ( #(.nextInt (java.util.Random.) 1000))}) 

(str (:c ab) " " (:c ab) " " (:c ab))

我明白了:

61 61 61

而不是三个不同的数字

更新2

我想到了我给出的答案并意识到他是对的,我应该只使用不可变结构。我想出的最终解决方案是拥有一个“丰富”功能,可以根据需要创建动态属性。

 (def a {:a 1, :b 2})

:我希望重载地图,以便某些关键字执行以下功能:

(str (:c (enrich ab)) " " (:c (enrich ab)) " " (:c (enrich ab)))
每次都会产生不同的数字:

58 639 710

3 个答案:

答案 0 :(得分:4)

如果您将数据结构设为记录而非常规地图,我相信可以覆盖关联查找的行为。

您基本上需要覆盖clojure.lang.ILookup:有关详细信息,请参阅this question

这是一个简单的例子:

(deftype TestLookup []
  clojure.lang.ILookup
    (valAt [this k not-found]
      (str "Generated value for key - " k))

    (valAt [this k]
      (.valAt this k nil)))

(def lookupable-object (TestLookup.))

(:somekey lookupable-object)
=> "Generated value for key - :somekey"

答案 1 :(得分:2)

使用相同的映射有时会传回不可变的值,有时会传回不纯函数,这似乎违背了应该使用不可变映射的精神。而不是这样做,我建议使用一个引用类型,它指向一个只有数据值的不可变映射。然后,当其中一个数据值需要不同时,将引用类型指向反映任何更改的新不可变映射。

答案 2 :(得分:2)

Clojure更喜欢纯数据结构,而不是结合数据和行为的对象。您可以通过函数访问数据结构来获得所需的行为:

(def base-foo {:a 1, :b 2})

(defn foo [key]
  (if (= :c key) 
    (rand-int 100)
    (get base-foo key)))

(str (foo :c) " " (foo :c) " " (foo :c))

;;=> "66 52 25"