2013-05-31 60 views
2

如何將符號重新綁定到Clojure中的新數據結構。例如:Clojure:將符號重新綁定到新的數據結構

(def hash-map-one {:a "foo" :b "bar"}) 
(def hash-map-two {:c "gaz" :d "waka"}) 

;; right here make hash-map-one equal to hash-map-two very quickly 
;; if this were python I would say hash-map-one = hash-map-two 

有點動機,我這樣做是因爲我有依賴於數據文件的Web服務,該數據文件將被更新,在這一點上,我需要,無需停機, 「切換」到新的數據。

在此先感謝!

+0

作爲附註,符號不是Clojure中的存儲位置。這裏的散列圖存儲在變量中。它們具有符號名稱,但可以在不同名稱空間中解析爲不同的變量。 (由於別名,這甚至適用於命名空間限定的符號。) –

回答

5

鑑於你的使用情況,使用原子可能最有意義:

(def data (atom {:map 'of :initial "data"})) 

(reset! data {:map 'of :new "data"}) 

如果由於某種原因,你更喜歡使用VAR,您可以使用alter-var-root切換到一個新的價值。你也可以使用intern,但是你會失去alter-var-root的原子性保證(參見文檔字符串和this answer;註釋:def同樣適用於intern)。

在REPL中,使用def來重新綁定現有的Vars非常好,但它在生產代碼中通常不是一個好主意(在Clojure實現中發現了一些明顯的異常 - 一個非常特殊的情況)。最重要的是,def應該只能用於立即執行它的頂層表單;也就是說,它應該是一個頂級的表單本身,或者像頂級表單的一部分,如let。否則weirdness ensues

+0

太棒了,謝謝你,很好的回答,我現在就探索一下。嘿,我只是在repl玩耍,做了一個前額,當我這樣做:'user =>(def x {:a 1:b 2}) #'user/x user =>(let [y { :c 3:d 4}](dosync(def xy)))'如果這將是一個全局變量(在服務器啓動時在jetty中創建),這是好的,還是有一些缺陷? –

+0

此外,如果這是在像Jetty這樣的線程websever中,我看到你的工作,將一個簡單的def語句? –

+1

我剛剛編輯了答案以添加一些額外的細節。 'def'不適合在函數內部使用(參見答案末尾的鏈接以便討論其原因);使用'intern'代替。順便說一句,你的第一個評論中的'dosync'什麼都不做,因爲沒有參與Refs。 –