REPL交互环境 #
一、REPL简介 #
REPL(Read-Eval-Print-Loop)是Clojure交互式开发的核心。它提供了一种即时反馈的开发体验,让你可以边写边测试代码。
1.1 REPL工作流程 #
text
┌─────────────────────────────────────────┐
│ │
│ Read → Eval → Print → Loop │
│ ↓ ↓ ↓ ↓ │
│ 读取 求值 打印 循环 │
│ │
└─────────────────────────────────────────┘
1.2 启动REPL #
Clojure CLI:
bash
clj
Leiningen:
bash
lein repl
nREPL(网络REPL):
bash
lein repl :headless
二、基本操作 #
2.1 表达式求值 #
clojure
user=> (+ 1 2 3)
6
user=> (defn square [x] (* x x))
#'user/square
user=> (square 5)
25
2.2 多行输入 #
clojure
user=> (defn greet
#_=> [name]
#_=> (str "Hello, " name "!"))
#'user/greet
REPL会自动检测括号匹配,等待完整输入。
2.3 特殊命令 #
| 命令 | 功能 |
|---|---|
(quit) 或 (exit) |
退出REPL |
(doc name) |
查看文档 |
(source name) |
查看源码 |
(find-doc "text") |
搜索文档 |
(apropos "text") |
搜索符号 |
(pst) |
打印堆栈跟踪 |
三、命名空间操作 #
3.1 当前命名空间 #
clojure
user=> *ns*
#object[clojure.lang.Namespace 0x... "user"]
3.2 创建命名空间 #
clojure
user=> (ns my-app.core)
nil
my-app.core=> *ns*
#object[clojure.lang.Namespace 0x... "my-app.core"]
3.3 切换命名空间 #
clojure
user=> (in-ns 'my-app.utils)
#object[clojure.lang.Namespace 0x... "my-app.utils"]
my-app.utils=> (ns user)
nil
3.4 查看命名空间内容 #
clojure
user=> (ns-publics 'clojure.string)
{:split #'clojure.string/split, :join #'clojure.string/join, ...}
user=> (ns-interns 'user)
{greet #'user/greet, square #'user/square}
user=> (ns-map 'user)
{...}
四、文档与源码 #
4.1 查看文档 #
clojure
user=> (doc map)
-------------------------
clojure.core/map
([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])
Returns a lazy sequence consisting of the result of applying f to
the set of first items of each coll, followed by applying f to the
set of second items in each coll, until any one of the colls is
exhausted. ...
4.2 查看源码 #
clojure
user=> (source when)
(defmacro when
[test & body]
(list 'if test (cons 'do body)))
4.3 搜索文档 #
clojure
user=> (find-doc "string")
user=> (find-doc #"regex")
user=> (apropos "map")
(map map? mapcat mapv ...)
4.4 查看元数据 #
clojure
user=> (meta #'map)
{:arglists ([f coll] [f c1 c2] ...),
:doc "Returns a lazy sequence...",
:line 2713,
:column 1,
:file "clojure/core.clj",
:name map,
:ns #object[clojure.lang.Namespace ...]}
五、调试技巧 #
5.1 打印调试 #
clojure
user=> (defn process [x]
(println "Input:" x)
(let [result (* x 2)]
(println "Result:" result)
result))
user=> (process 5)
Input: 5
Result: 10
10
5.2 使用pr和prn #
clojure
user=> (pr {:a 1 :b 2})
{:a 1, :b 2}
user=> (prn {:a 1 :b 2})
{:a 1, :b 2}
nil
5.3 堆栈跟踪 #
clojure
user=> (/ 1 0)
ArityException...
user=> (pst)
ArityException Dividing by zero
clojure.lang.Numbers.divide (Numbers.java:163)
user/eval123 (NO_SOURCE_FILE:1)
...
nil
5.4 使用tap> #
Clojure 1.10+ 提供的调试工具:
clojure
user=> (add-tap println)
#object[...]
user=> (tap> {:debug "data"})
{:debug "data"}
true
user=> (remove-tap println)
六、热重载 #
6.1 加载文件 #
clojure
user=> (load-file "src/my_app/core.clj")
6.2 重新加载命名空间 #
clojure
user=> (use 'my-app.core :reload)
user=> (require '[my-app.core :as core] :reload)
6.3 使用tools.namespace #
clojure
user=> (require '[clojure.tools.namespace.repl :refer [refresh]])
user=> (refresh)
:reloading (my-app.core my-app.utils)
:ok
七、REPL历史 #
7.1 历史导航 #
| 快捷键 | 功能 |
|---|---|
| ↑ | 上一条命令 |
| ↓ | 下一条命令 |
| Ctrl+R | 搜索历史 |
7.2 保存历史 #
Leiningen自动保存REPL历史到 .lein/repl-history。
八、编辑器集成 #
8.1 Calva (VS Code) #
连接REPL:
- 打开Clojure文件
Ctrl+Alt+C Enter连接Ctrl+Enter求值当前表达式
常用命令:
| 快捷键 | 功能 |
|---|---|
Ctrl+Enter |
求值当前表达式 |
Alt+Enter |
求值顶层表达式 |
Ctrl+Alt+C Space |
求值选中代码 |
Ctrl+Alt+C Ctrl+L |
加载当前文件 |
8.2 CIDER (Emacs) #
启动REPL:
text
M-x cider-jack-in
常用命令:
| 快捷键 | 功能 |
|---|---|
C-x C-e |
求值表达式 |
C-c C-k |
加载当前文件 |
C-c M-n |
切换命名空间 |
C-c C-d d |
查看文档 |
8.3 Cursive (IntelliJ) #
启动REPL:
- 右键项目 → Run REPL
- 或使用
lein repl
常用操作:
Ctrl+Shift+L求值表达式Ctrl+Shift+P加载文件
九、高级技巧 #
9.1 自定义REPL提示符 #
clojure
user=> (set! *print-length* 10)
10
user=> (range 100)
(0 1 2 3 4 5 6 7 8 9 ...)
9.2 捕获异常 #
clojure
user=> (try
(/ 1 0)
(catch Exception e
(str "Error: " (.getMessage e))))
"Error: Divide by zero"
9.3 时间测量 #
clojure
user=> (time (reduce + (range 1000000)))
"Elapsed time: 23.456 msecs"
499999500000
9.4 查看Java类 #
clojure
user=> (class "hello")
java.lang.String
user=> (class 42)
java.lang.Long
user=> (class [1 2 3])
clojure.lang.PersistentVector
十、REPL工具库 #
10.1 clojure.repl #
clojure
user=> (require '[clojure.repl :refer [doc source pst]])
user=> (doc map)
user=> (source when)
user=> (pst)
10.2 clojure.test #
clojure
user=> (require '[clojure.test :refer [deftest is run-tests]])
user=> (deftest my-test
(is (= 1 1))
(is (= 2 (+ 1 1))))
user=> (run-tests)
10.3 clojure.pprint #
clojure
user=> (require '[clojure.pprint :refer [pprint]])
user=> (pprint {:a 1 :b {:c 2 :d 3}})
{:a 1,
:b {:c 2,
:d 3}}
十一、最佳实践 #
11.1 开发流程 #
- 在编辑器中编写代码
- 发送到REPL求值测试
- 交互式调试
- 保存文件
- 定期刷新命名空间
11.2 REPL友好代码 #
clojure
(defn process-data
[data]
(let [cleaned (filter valid? data)
transformed (map transform cleaned)]
transformed))
将复杂逻辑拆分为小函数,便于在REPL中测试。
11.3 避免状态污染 #
clojure
user=> (ns my-test
(:require [my-app.core :as core]))
my-test=> (core/process ...)
使用独立命名空间测试,避免污染主命名空间。
十二、总结 #
REPL开发的核心优势:
- 即时反馈:快速验证想法
- 交互调试:逐步排查问题
- 探索式编程:边写边学
- 热重载:无需重启应用
REPL使用技巧:
- 熟练使用
doc、source、find-doc - 掌握编辑器集成快捷键
- 利用
tap>和pst调试 - 定期刷新命名空间
REPL是Clojure开发的核心工具,熟练使用REPL将大大提升开发效率!
最后更新:2026-03-27