Setting Clojure “constants” at runtime

百般思念 提交于 2019-12-04 02:52:02

I still think the cleanest way is to use alter-var-root in the main method of your application.

(declare version)

(defn -main
  [& args]
  (alter-var-root #'version (constantly (-> ...)))
  (do-stuff))

It declares the Var at compile time, sets its root value at runtime once, doesn't require deref and is not bound to the main thread. You didn't respond to this suggestion in your previous question. Did you try this approach?

You could use dynamic binding.

(declare *version*)

(defn start-my-program []
  (binding [*version* (read-version-from-file)]
    (main))

Now main and every function it calls will see the value of *version*.

While kotarak's solution works very well, here is an alternative approach: turn your code into a memoized function that returns the version. Like so:

(def get-version
 (memoize
  (fn []
    (-> (str "jar:" (-> my.ns.name (.getProtectionDomain)
            (.getCodeSource)
            (.getLocation))
         "!/META-INF/MANIFEST.MF")
    (URL.)
    (.openStream)
    (Manifest.)
    (.. getMainAttributes)
    (.getValue "Build-number")))))

I hope i dont miss something this time.

If version is a constant, it's going to be defined one time and is not going to be changed you can simple remove the defn and keep the (def version ... ) alone. I suppose you dont want this for some reason.

If you want to change global variables in a fn i think the more idiomatic way is to use some of concurrency constructions to store the data and access and change it in a secure way For example:

(def *version* (atom ""))

(defn set-version! [] (swap! *version* ...))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!