生成名稱的願望,意味着你將會通過一個單一的地圖,而不是得到更好的服務:
(def neighbours (atom (make-neighbours)))
凡make-neigbours
的定義可能是這個樣子:
(defn make-neighbours []
(into {} (for [i (range 10)]
[(str "neig" i) {:age i}])))
當其他命名空間會看起來像使用類似的值:
(get-in @data/neighbours ["neig0" :age])
習慣性Clojure傾向於避免創建許多命名的全局變量,而寧願將狀態並置到由Clojure的併發原語(atom/ref/agent)控制的一個或幾個變量中。我鼓勵你想想你的問題是否可以用這種方式用單個原子來解決,而不是要求定義多個變量。儘管如此,如果您真的需要多個原子,請考慮將它們全部存儲在一個地圖var中,而不是創建許多全局變量。就我個人而言,我從來沒有遇到過創建多個原子比單個大原子更好的情況(所以我會有興趣知道這種情況很重要)。
如果您確實需要很多變量,請注意,在函數中定義變量實際上是不好的樣式(https://github.com/bbatsov/clojure-style-guide#dont-def-vars-inside-fns)。也有很好的理由!使用功能和數據的美妙來自於功能的純粹性。 def
函數內部特別討厭,因爲它不僅是一種副作用,而且是一種潛在的執行流改變副作用。
當然是有一種方法可以實現它,正如另一個答案指出的那樣。
說到定義超出def
和defn
的東西,使用宏有很多優先權。例如來自compojure的defroutes
,來自Schema的defschema
,來自clojure.test的deftest
。一般來說,任何創建變量的方便形式都可以。你可以使用宏的解決方案,爲您創造原子DEFS:
(defmacro defneighbours [n]
`(do
[email protected](for [sym (for [i (range n)]
(symbol (str "neig" i)))]
`(def ~sym (atom {}))))
在我看來,這是不是一個功能版本的攻勢居然少,不僅因爲它是創造全球DEFS。通過使用常規的def
語法來創建全局視圖更爲明顯。但我只是把它作爲一個稻草人來提出來,因爲這仍然很糟糕。
功能和數據效果最好的原因是因爲它們組成。
有一些有形的考慮因素使得單個原子控制狀態非常方便。您可以方便地遍歷所有鄰居,您可以動態添加新鄰居。你也可以做一些事情,如連接鄰居和其他鄰居等。基本上有很多功能/數據抽象,如果你創建了許多全局變量,你就會鎖定自己。
這就是宏一般認爲對語法技巧有用的原因,但最好避免使用函數和數據。它對代碼的靈活性有着實際的影響。例如回到組合;宏語法實際上是非常有限的,因此我寧願不使用defroutes
。
總結:
- 不要讓許多全球DEFS的,如果你能避免它。
- 在可能的情況下,優先選擇多個原子上的1個原子。
- 不要在函數內部定義。
- 最好避免使用宏來支持函數和數據。
- 無論這些指導方針如何,探索什麼是可能的,並且我無法瞭解您的情況總是很好的,所以我希望您最終克服了您的直接問題,並找到了一種令人愉快的語言來使用Clojure。
但是,你的功能的實際問題是什麼?你在當前命名空間中生成符號,所以你只需要用'atom'調用來包裝你的向量。 – leetwinski