2015-07-09 10 views
9

Podstawowy problem, który próbuję rozwiązać, to: mieć obiekt settings, który jest ładowany z settings.json file, za każdym razem, gdy program jest uruchamiany.Clojure - jak tworzyć formularze def oceniać w czasie wykonywania zamiast kompilacji

I Kod początkowo używany jak

(def settings (load-settings "settings.json"))

ale podczas deploy Byłem zaskoczony, aby dowiedzieć się, że forma startowych jest oceniany w czasie kompilacji zamiast czasu pracy - kompilacja została niepowodzeniem, ponieważ nie było settings.json plik na miejscu.

Więc częścią Y problemu jest - czy mogę opóźnić ocenę formuły init bez użycia refs lub w inny sposób komplikując użycie obiektu? Czy może brakuje tu jakiejś podstawowej koncepcji?

+2

Czy kompilujesz przestrzeń nazw AOT? Czy to dzieje się w momencie wyjątku? – Alex

Odpowiedz

8

Odpowiadając na moje własne pytanie, ponieważ znalazłem dokładnie to, czego chciałem, dzięki @Alex.

Tak, cytując this thread from the Clojure mailing list from 2008,

Podczas kompilacji, a kompilacji plików flaga jest ustawiona. [...] Jeśli plik ma pewne inicjatorów def nie chcesz, aby uruchomić w czasie kompilacji, można conditionalize je tak:

(def foo (when-not *compile-files* (my-runtime-init)))

w takim przypadku foo będzie zerowa w czas kompilacji.

testowałem zachowanie z następującego kodu:

(def evaluated-at-runtime 
    (when-not *compile-files* 
    (println "i am evaluated") 
    "value")) 

(defn -main [& args] 
    (println evaluated-at-runtime)) 


>lein uberjar 
... "(i am evaluated)" is not printed) 

>java -jar test-app.jar 
i am evaluated 
value 

istnieje zastrzeżenie tutaj, że forma startowych będą oceniane tak szybko, jak program jest uruchomiony, przed zastosowaniem metody -main, może to nie być wystarczająco elastycznym dla wszystkich, ale potem kieruję cię do jednej z innych wspaniałych odpowiedzi na to pytanie.

8

Jednym z możliwych rozwiązań jest leniwe ładowanie pliku ustawień, tzn. Po raz pierwszy jest on używany. Można to zrobić z delay macro:

(def settings 
    (delay (load-settings "settings.json"))) 

Jedyną różnicą jest to, że będziesz musiał deref Twój obiekt settings za każdym razem będziemy chcieli z niego korzystać:

(println @settings) 
0

przyszłość i Opóźnienie może być użyte.

future działa w tle i unika czekania na zakończenie oceny.

delay nie zrobi niczego, co spróbuje uzyskać dostęp do wartości.

(def string-sample "(do (Thread/sleep 5000) (println \"done\") 1)") 

; execute immediately 
(def settings (load-string string-sample)) 
(println settings) 

; execute in the background, returns immediately 
(def settings (future (load-string string-sample))) 
(println @settings) 

; evaluated when calling it 
(def settings (delay (load-string string-sample))) 
(println @settings) 
0

Co nie wystarczy użyć defn zamiast def.

(defn settings [] (load-settings "settings.json")) 

Następnie użyj (settings) zamiast settings.

+1

Ponieważ w wielu przypadkach odnoszą się do 'ustawień' wiele razy, czasami setki razy na sekundę, a nie chcesz czytać i parsować pliku za każdym razem, gdy potrzebujesz dostępu do ustawień. – Philip

Powiązane problemy