LISP - 交互式 I/O
Lisp - 现代交互式和文件 I/O
Section titled “Lisp - 现代交互式和文件 I/O”交互式 I/O 是 Lisp 开发体验的核心,其典型代表是 REPL(读取-求值-打印循环)。本章将介绍处理 I/O 的现代方法,从与用户交互到稳健地管理文件。
REPL:您的交互式网关
Section titled “REPL:您的交互式网关”REPL 不仅仅是一个命令行;它是一个强大、动态的开发环境。典型的工作流程是:
- 读取(Read):REPL 读取您输入的 Lisp 表达式。
- 求值(Eval):它求值(执行)该表达式。
- 打印(Print):它将求值结果打印回给您。
- 循环(Loop):它等待您的下一次输入。
现代 Lisp 环境,如 SLIME(适用于 Emacs)或 SLY(适用于 Emacs/VS Code),极大地增强了 REPL 的功能,允许您交互式地编译文件、检查对象和调试代码。
核心概念:流(Streams)
Section titled “核心概念:流(Streams)”流(Stream) 是 Lisp 中 I/O 的基本抽象。它代表数据的来源或目的地。Common Lisp 提供了几个标准流以方便使用:
*standard-input*:默认输入流,通常连接到键盘。*standard-output*:默认输出流,通常是终端显示器。*error-output*:用于错误消息的流,通常也是终端。*terminal-io*:一个特殊的双向流,用于与用户直接交互。
关键 I/O 函数
Section titled “关键 I/O 函数”read:从流中读取一个完整的 Lisp 表达式(S-表达式)。它将文本解析为 Lisp 对象。read-line:将一行文本作为字符串读取,并消耗换行符。read-char:从流中读取一个字符。
print:打印一个 Lisp 对象,前面有一个换行符,后面有一个空格。设计为机器可读(可以使用read再次读取)。prin1:类似于print,但没有换行符和空格。princ:以更易于人类阅读的格式打印对象(例如,不带引号的字符串)。write:一个高度可配置的打印对象函数。format:最强大的输出函数。它使用控制指令创建格式化字符串。
精通 format
Section titled “精通 format”format 是一个多功能的工具,用于生成结构化文本。它的第一个参数是目标流(t 表示 *standard-output*,nil 表示返回一个字符串),后面跟着一个控制字符串和参数。
;; `format` 使用示例
(defparameter *user-name* "Alex")(defparameter *items-count* 5)
;; 打印到标准输出(format t "Hello, ~a! You have ~d items.~%" *user-name* *items-count*)
;; 使用的指令:;; ~a : 美学(人类可读)表示;; ~d : 十进制整数;; ~% : 换行符
;; 使用 nil 作为目标创建格式化字符串(defparameter *message* (format nil "Report for user: ~s" *user-name*))
(print *message*);; ~s : 标准(机器可读)表示Hello, Alex! You have 5 items."Report for user: \"Alex\""现代文件 I/O:with-open-file
Section titled “现代文件 I/O:with-open-file”虽然 open 和 close 存在,但处理文件的现代且安全的方式是使用 with-open-file 宏。即使在其主体中发生错误,它也会自动处理文件流的关闭。这可以防止资源泄漏。
(with-open-file (stream-variable filespec options*) ;; 使用 stream-variable 的代码 )示例:写入和读取文件
Section titled “示例:写入和读取文件”;; --- 写入文件 ---(with-open-file (out "/tmp/my-data.txt" :direction :output :if-exists :supersede) ;; 如果文件存在则覆盖 (format out "This is line 1.~%") (format out "This is line 2.~%"))
(format t "File 'my-data.txt' written successfully.~%~%")
;; --- 读取文件 ---(format t "Contents of 'my-data.txt':~%")(with-open-file (in "/tmp/my-data.txt" :direction :input) (loop for line = (read-line in nil) ;; 读取行,文件结束时返回 nil while line do (format t "> ~a~%" line)))File 'my-data.txt' written successfully.
Contents of 'my-data.txt':> This is line 1.> This is line 2.下一步:项目管理
Section titled “下一步:项目管理”对于实际项目,您不会只在 REPL 中输入代码。您会将代码组织成文件和项目。标准工具包括:
- ASDF(Another System Definition Facility,另一个系统定义工具):Common Lisp 事实上的构建系统。您通过定义
.asd文件来指定哪些文件属于您的项目(或“系统”)。 - Quicklisp:Common Lisp 事实上的库管理器。它允许您轻松下载、安装和加载数千个开源库。