clojure,dynamic-var,需要宏吗?

时间:2016-11-09 07:33:25

标签: clojure

背景

我正在尝试编写以下函数:

  (defn cache-get [dynamic-var k func]
    (if-let [v (get-in dynamic-var k)]
      v
      (let [ans (func)]
        (set! dynamic-var (assoc-in dvar k ans))
        ans)))

cache-get的参数是:

  • dynamic-var,类似于(def ^:dynamic *my-local-cache*)
  • k,一键,类似于:foo
  • func,一个函数,如果值不存在则被调用

该功能的行为是:

  • 如果密钥k存在,只需返回值
  • 如果密钥k不存在,(1)通过调用(func)计算它并且(2)将其存储在缓存中

我正面临的问题

我面临的问题是我显然可以(set! dynamic-var ...),因为函数不知道我会将它传递给动态绑定的var并且认为dynamic-var是一个常规变量。

我当前的选择:

将该函数重写为宏 - 这很好,但除非绝对必要,否则我不想使用宏。

我的问题:有没有办法在不使用宏的情况下实现cache-get

[另外,我希望这是一个动态变量,而不是原子]

谢谢!

编辑1

我尝试var-set的建议。我收到以下错误:

(def ^:dynamic *query-ctx* {})

(defn cache-get [dynamic-var k func]
  (if-let [v (get-in dynamic-var k)]
    v
    (let [ans (func)]
      (var-set dynamic-var (assoc-in dynamic-var k ans))
      ans)))

(cache-get *query-ctx* [:foo-key] (fn [] :foo-value))

;; clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.Var

1 个答案:

答案 0 :(得分:1)

要回答这个问题:您需要var-set而不是set!

快速提问:如果您传入变量,是否真的需要动态变量?

  

[另外,我希望这是一个动态变量,而不是原子]

你可以扩展吗?看起来原子似乎是一个更合乎逻辑的选择。您是否需要该缓存的特定于线程的版本?

更新:示例电话:

(cache-get #'*query-ctx* [:foo-key] (fn [] :foo-value))