質問

I'm trying to find the idiomatic way to defer the initialization of a var (which I really intend to be immutable).

(def foo nil)
...
(defn init []
  ; (def foo (some-function))
  ; (set! foo (some-function)))

I know Rich Hickey said re-defing isn't idiomatic. Is set! appropriate here?

役に立ちましたか?

解決

I would use delay:

Takes a body of expressions and yields a Delay object that will invoke the body only the first time it is forced (with force or deref/@), and will cache the result and return it on all subsequent force calls. See also - realized?

Example usage:

(def foo (delay (init-foo))) ;; init-foo is not called until foo is deref'ed

(defn do-something []
  (let [f @foo] ;; init-foo is called the first time this line is executed,
                ;; and the result saved and re-used for each subsequent call.
    ...
    ))

他のヒント

Besides using delay as Alex states in his answer, set! works just fine because vars are just javascript variables under the hood.

Yous shouldn't really directly set! vars like this, but for special cases like this I personally allow myself to (sparingly) do so (ie the data actually is normal immutable Clojure once set up). One example where I do this is to override functions in debug builds:

(defn foo [] release code here)

Then in a file that is added only to debug builds:

(defn debug-foo []
  (.log js/console "foo called"))
(set! foo debug-foo)
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top