簡體   English   中英

什么時候通過nREPL重新加載名稱空間不夠,整個服務器進程(甚至REPL)都需要重新啟動?

[英]When is reloading a namespace via nREPL not enough and whole server process (or even the REPL) needs to be restarted?

我使用nREPL和Emacs的Cider模式玩了一些之后,發現有時我不得不重新啟動http-kit服務器以使其接受更改(通常是在更改中間件或路由時),混亂,我只需要重新啟動整個REPL。

我很難找出實際上是什么原因造成的。 似乎有時我什至可以更改諸如路由定義(使用compojure defroutes宏定義)之類的東西,並且運行中的服務器會接管事情,有時它不起作用,並且我必須停止服務器並重新啟動它。

Clojure中是否有任何特定的模式可以使重新加載更加容易? 還是無法迫使整個REPL重新加載的事情? 我還發現有時我會評估一些東西,例如混亂的導入,這迫使我重新啟動整個REPL。

是否有任何最佳實踐可服務器運行時 使代碼輕松地重新加載 (例如通過Cider中的Cc Ck,以便自動獲取更改 我想我很久以前就已經看到過一些東西,可以通過添加一個間接層來使最愚蠢的Web服務器重新加載東西,但是我似乎並沒有真正找到它的所在。

以我的經驗,REPL中兩個最常見的陳舊代碼來源是高階函數和AOT編譯。

高階函數

當您使用諸如comppartial類的高階函數時,該函數將某個函數作為輸入來實現一些應用程序邏輯並返回一個調用該函數的新函數,那么將捕獲調用HOF時函數的定義。 輸入函數定義的后續更改不會反映在輸出函數中。

user=> (defn a [x y] (+ x y))
user=> (def b (partial a 2))
user=> (defn c [y] (a 2 y))
user=> (b 3)
5
user=> (c 3)
5
user=> (defn a [x y] (* x y))
user=> (b 3)
5
user=> (c 3)
6

在上面的例子中,如果a在命名空間中定義foob是命名空間中定義bar ,然后重裝foo不會改變的行為b除非你也重新加載bar 如該示例中所建議,如果定義更改,則在調用代碼中按名稱調用該函數將導致調用新定義。

這與Web開發有關,因為Clojure Web開發的許多基礎結構都集中在高階功能上(即,中間件實質上是功能組成)。 您應該根據自己的判斷來決定在習慣上使用高階函數和在開發過程中輕松重新加載代碼之間的適當平衡。

AOT編譯

一些Clojure功能(即deftypedefrecorddefprotocol )會導致生成Java類和接口,然后在Clojure代碼中的其他地方以它們的Java類名對其進行引用。 當您對該代碼進行AOT編譯時,將為這些Java類發出.class文件,這些文件隨后出現在REPL類路徑上。 加載Java類時,總是優先選擇.class文件中的定義,而不是動態生成的類定義。 通過這些機制之一重載用於定義Java類的名稱空間不會產生任何效果。 您必須重新啟動REPL。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM