我正在尝试实现一个get-database
函数,该函数在第一次调用Monger时从Monger检索数据库引用,记住原子中的值,并在随后的调用中直接返回。我当前的代码如下:
(def database (atom nil))
(defn get-database
[]
(compare-and-set! database nil
(let [db (:db (mg/connect-via-uri (System/getenv "MONGOLAB_URI")))] db))
@database)
问题是,即使compare-and-set!
返回false(即database
不是nil
),let
子句似乎也会被求值。有没有什么方法可以让它进行懒惰的评估,这样我就不会因为检索Monger连接而受到惩罚,或者这种方法从根本上被误导了?
这里的问题是compare-and-set!
是一个函数,因此对其求值将在调用函数之前对所有参数进行求值。
对于缓存和重新使用一些昂贵的计算值的用例,我采用的典型方法是使用delay
:
获取一组表达式并生成一个Delay对象,该对象将仅在第一次强制(使用force或deref/@)时调用主体,并且将缓存结果并在所有后续部队中返回电话。也看到了——实现了吗?
在您的情况下:
(def database (delay (:db (mg/connect-via-uri (System/getenv "MONGOLAB_URI")))))
现在,只要您想在任何时候获得对数据库的引用,就可以说@database
,并且在您的代码第一次实际导致延迟被取消引用时,连接就会被初始化。如果愿意的话,可以将调用封装在get-database
函数中以取消引用延迟,但这不是必须的。