Clojure

REPL 和主要入口點

clojure.main 命名空間

clojure.main 命名空間提供函數,可讓 Clojure 程式和互動式工作階段透過 Java 的應用程式啟動工具 java 啟動。

clojure.main --help

clojure.main/main 進入點接受各種引數和旗標。

  • 沒有選項或引數時,執行互動式讀取-評估-列印迴圈

  • 初始化選項

    • -i, --init 路徑載入檔案或資源

    • -e, --eval 字串評估字串中的表達式;列印非 nil 值

    • --report 目標將未捕捉到的例外報告至「檔案」(預設值)、「stderr」或「none」,覆寫系統屬性 clojure.main.report (於 1.10.1 中新增)

  • 主選項

    • -r, --repl 執行 repl

    • 路徑從檔案或資源執行指令碼

    • - 從標準輸入執行指令碼

    • -m, --main 尋找命名空間以執行 -main 函數

    • -h, -?, --help 列印此說明訊息並結束

  • 操作

    • 為通常可設定的變數建立執行緒本機繫結。

    • 進入使用者命名空間。

    • *command-line-args* 繫結至包含出現在任何主選項後的命令列引數的字串序列。

    • 依序執行所有初始化選項。

    • 如果要求,執行 repl 或指令碼。

初始化選項可以重複且自由混合,但必須出現在任何主選項之前。在執行 repl 之前出現任何 eval 選項,會抑制通常的 repl 問候訊息:「Clojure ~(clojure-version)」。

路徑可以是檔案系統中的絕對路徑或相對路徑,或相對於類別路徑。相對於類別路徑的路徑有 @ 或 @/ 前綴。

啟動 REPL

啟動 Clojure repl 最簡單的方法是使用 clj 命令工具,它會呼叫 clojure.main

$ clj
Clojure 1.11.2
user=>

REPL 提示會顯示目前命名空間 (*ns*) 的名稱,預設為 user

使用 REPL 時有幾個特殊變數可用

  • *1, *2, *3 - 保留已評估的最後三個表達式的結果

  • *e - 保留最後一個例外的結果。

clojure.repl」命名空間有許多有用的函式,可用於檢查可用函式的來源和文件

  • doc - 根據變數名稱列印其文件字串

  • find-doc - 列印文件字串,其文件或名稱符合模式

  • apropos - 傳回與正規表示式相符的定義序列

  • source - 列印符號的來源

  • pst - print stack trace,針對指定的例外狀況,或預設為 *e

啟動腳本

若要執行包含 Clojure 程式碼的檔案作為腳本,請將腳本路徑傳遞給 clojure.main 作為引數

clj -M /path/to/myscript.clj

傳遞引數給腳本

若要傳遞引數給腳本,請在啟動 clojure.main 時將其傳遞為進一步的引數

clj -M /path/to/myscript.clj arg1 arg2 arg3

引數會以字串序列的形式提供給您的程式,並繫結到變數 *command-line-args*

*command-line-args* => ("arg1" "arg2" "arg3")

列印錯誤

在 REPL 中

從 Clojure 1.10 開始,Clojure 錯誤會分類為幾個階段之一

  • :read-source - 在 REPL 或來源檔案中讀取字元時引發的錯誤。

  • :macro-syntax-check - 在巨集呼叫語法中找到的語法錯誤,可能是來自規範或引發 IllegalArgumentException、IllegalStateException 或 ExceptionInfo 的巨集。

  • :macroexpansion - 巨集評估期間引發的所有其他錯誤都歸類為巨集擴充錯誤。

  • :compile-syntax-check - 編譯期間捕獲的語法錯誤。

  • :compilation - 編譯期間捕獲的非語法錯誤。

  • :execution - 執行時間引發的任何錯誤。

  • :read-eval-result - 讀取執行結果時引發的任何錯誤(僅適用於讀取結果的 REPL)。

  • :print-eval-result - 列印執行結果時引發的任何錯誤。

在所有階段(:execution 例外)期間引發的例外狀況將附加 ex 資料,其中包含下列一個或多個金鑰

  • :clojure.error/phase - 階段指標

  • :clojure.error/source - 檔案名稱(無路徑)

  • :clojure.error/line - 整數行號

  • :clojure.error/column - 整數欄位號

  • :clojure.error/symbol - 正在展開/編譯/呼叫的符號

  • :clojure.error/class - 原因例外類別符號

  • :clojure.error/cause - 原因例外訊息

  • :clojure.error/spec - 規格錯誤的說明資料

預設情況下,clojure.main REPL 包含錯誤分類和列印,但此程序的個別步驟也公開供其他 REPL 使用,特別是以下函數

  • Throwable->map - 將例外鏈轉換為 Clojure 資料

  • ex-triage - 分析 Clojure 例外資料,從例外鏈的頂部和底部擷取相關資訊,並放入一個描述格式化例外字串所需資料集的映射中

  • ex-str - 根據一組例外資料產生階段適當的訊息

clojure.main REPL 將這些函數組合成一個管線,以產生列印的例外訊息:(-> ex Throwable->map clojure.main/ex-triage clojure.main/ex-str)。其他 REPL 在建立或自訂其例外列印時,可以根據需要使用此管線的一個或多個部分。

作為啟動器

在 Clojure 1.10.0 之前,當 clojure.main 用作程式啟動器(使用 -m、-e 或使用腳本)時,未捕捉的例外會自動列印,並附上完整的巢狀堆疊追蹤。在此情況下,不會套用上述錯誤分類和列印程序。

從 Clojure 1.10.1 開始,未捕捉的例外現在會根據與 Clojure REPL 相同的錯誤分類和列印功能進行捕捉和列印。完整的堆疊追蹤、ex-info 和其他資訊將列印到由組態指定的目標。

三種可用的錯誤目標為

  • file - 寫入暫存檔(預設,退回至 stderr

  • stderr - 寫入 stderr 串流

  • none - 不寫入

這些錯誤目標可以指定為 clojure.main 的選項,或作為 Java 系統屬性(旗標優先)。呼叫 clojure.main(或使用 clj 工具)時,請使用 --report <target>。對於 Java 系統屬性,請使用 -Dclojure.main.report=<target>

其他程式可能希望利用此功能,而此功能可在 report-error 中取得,該功能會接收一個 Throwable,並選擇性地接收 :target。

user 名稱空間

預設情況下,Clojure REPL 會在 user 名稱空間中啟動,而這個名稱空間通常用於探索性工作。

Clojure REPL 會自動載入下列名稱空間,並參照下列函數

如果您切換到不同的名稱空間(使用 in-nsns),這些函數將不可用,除非在那裡明確參照。

載入 user.clj

如果在類別路徑中找到 user.clj,Clojure 執行時期會在執行時期啟動時尋找並載入它。這是一個旨在提供開發時期功能的工具,通常不建議在生產環境中使用。

由於 user.clj 檔案是由 Clojure 執行時期在初始化時載入的,因此這通常會在應用程式中的主名稱空間執行之前發生。因此,由 user.clj 載入的任何名稱空間或資源都會影響應用程式的啟動時間。

tap

tap 是可共用、可全局存取的系統,用於將一系列資訊或診斷值分發到一組(假設會產生效應的)處理函數。它可以用作更好的除錯 prn,或用於記錄等功能。

tap> 將值傳送給一組 taps。可以使用 add-tap 來新增 taps,並且會使用傳送給 tap> 的任何值來呼叫它們。tap 函數可能會(簡短地)封鎖(例如,對於串流),並且永遠不會阻礙對 tap> 的呼叫,但無限期封鎖可能會導致 tap 值被捨棄。如果沒有註冊任何 taps,tap> 會捨棄。使用 remove-tap 來移除 taps。

啟動 Socket 伺服器

Clojure 執行時期現在有能力在初始化時根據系統屬性啟動 socket 伺服器。預期的用途之一是提供基於 socket 的 REPL,但它還有許多其他潛在用途,可以在不變更程式碼的情況下動態新增伺服器功能到現有程式中。

將為每個 JVM 系統屬性(如「clojure.server.<server-name>」)啟動一個 socket 伺服器。此屬性的值是一個 edn 地圖,表示 socket 伺服器的設定,具有下列屬性

  • server-daemon - 預設為 true,socket 伺服器執行緒不會封鎖退出

  • address - 主機或位址,預設為回傳

  • port - 正整數,必填

  • accept - socket 接受時要呼叫的函數的命名空間符號,必填

  • args - 要傳遞給 accept 的順序收集的引數

  • bind-err - 預設為 true,將 *err* 繫結到 socket 輸出串流

  • client-daemon - 預設為 true,socket 客戶端執行緒不會封鎖退出

此外,還提供了一個 repl 函數,針對在 clojure.core.server/repl 中與 socket 伺服器一起使用而進行了輕微自訂。

以下是使用 repl 偵聽器啟動 socket 伺服器的範例。這可以新增到任何現有的 Clojure 程式中,以允許它透過與埠 5555 的本地連線接受外部 REPL 客戶端。

-Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}"

使用 Clojure CLI 時,請使用 -J 旗標將選項傳遞給 JVM(請注意,這也會啟動一個本地 REPL,除了 socket REPL 之外)

clj -J-Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}"

您可以用來遠端連線到此 repl 的範例客戶端是 telnet(也可以使用 netcat

$ telnet 127.0.0.1 5555
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
user=> (println "hello")
hello

您可以使用特殊指令 :repl/quit 指示伺服器關閉客戶端 repl 會話

user=> :repl/quit
Connection closed by foreign host.

另請參閱

主要進入點:clojure.main/main

可重複使用的 REPL:clojure.main/repl

允許 set! 用於慣例 REPL 變數:clojure.main/with-bindings

Socket repl:clojure.core.server/repl