【问题标题】:Clojure: How to initialize a def from a file at startup?Clojure:如何在启动时从文件初始化def?
【发布时间】:2015-09-19 08:25:36
【问题描述】:

我有以下 clojure 代码来初始化我的配置结构 Config。 我注意到文件实际上是在编译文件时读取的,而不是在运行时。

对我来说,配置结构 Config 应该是不可变的,但是,我不想将配置放在 JAR 文件中。

我应该怎么做?我必须使用原子吗?如果 my.config 丢失,应用程序崩溃也没关系。

(def Config
  (read-string (slurp "my.config")))

【问题讨论】:

  • 文件在编译时被读取,但你确定它没有在应用启动时被读取吗?
  • 是的,我确定现在是编译时间,因为如果文件不存在,“lein compile”会中止。
  • 我想你可能会发现它在编译时和应用启动时都在被读取。

标签: clojure


【解决方案1】:

如果在编译时不需要它,则必须将其包装在一个函数中。

(defn def-my-conf []
  (def Conf (blub)))

但你更干净的方法是:

(declare Config)

(defn load-Config []
 (alter-var-root (var Config) (blub)))

这个函数应该在你的 main 中调用。

编辑:当然,原子也是一种解决方案!

【讨论】:

  • 这个解决方案和下面的解决方案都有同样的问题。我需要编辑-main。如果我不想更改 -main,我有什么选择?任何类似于 Clojure 中的静态构造函数的东西。我没有意识到像 Ocaml 这样的 Clojure 和 ML 对于何时执行文件中的代码有如此不同的定义?在 ML 中,它们在加载程序的“同时”执行,并且经常用于收集或准备全局信息。
【解决方案2】:

写一个函数来读取你的配置:

(defn read-config
  []
  (read-string
   (slurp "my.config")))

然后你可以从 -main 调用这个函数,或者 1) 将配置传递给任何需要它的函数,或者 2) 将它存储在一个动态变量中并让它们直接读取它:

(def ^:dynamic *config* nil)

(defn some-function-using-config
  []
  (println *config*))

(defn -main
  []
  (binding [*config* (read-config)]
    (some-function-using-config)))

两者中选择哪一个是品味和情况的问题。通过直接传递,您可以明确地表明一个函数正在接收配置,使用动态变量,您可以避免将配置作为参数包含在您编写的每个函数中,大多数函数只会传递它。

这两种解决方案都适用于单元测试,因为您只需将动态变量重新绑定到您想用于每个测试的任何配置。

【讨论】:

    【解决方案3】:

    TheQuickBrownFox 给出了答案,文件在运行时和编译时都被读取。

    对我来说很好!这真的很酷!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-24
      • 2013-01-12
      相关资源
      最近更新 更多