目前正在学习SBCL的Common Lisp,它一直在困扰我查询io与标准输入和输出有一些意想不到的差异。我假设标准输出包含一个换行符,或者用换行符格式化,因为
(format *query-io* "hello")
根本不包含换行符。
现在,使用read行给我这个行为
(defun read (prompt)
(format *query-io* "~a: " prompt)
(read-line))
(read "message")
> hello
"hello"
message: NIL
我被告知这是意料之中的事,因为SBCL会在打印格式之前等待输入新行,但我没有得到的是更改第二行的结果
(defun read (prompt)
(format *standard-output* "~a: " prompt)
(read-line))
(read "message")
> hello
message:
"hello"
NIL
为什么顺序不同?我不认为提示变量后面的换行符会影响的结果
如果你想让事情以可预测的方式进行,你应该编写程序来确保:
- 不要将函数命名为
read
(事实上,我非常确信SBCL不会允许您将函数命名成read
,除非您使用的是史前版本) - 要清楚你实际阅读和写作的方向
- 如果您希望输出在给定的时间出现,请说您愿意
所以在你的第一个函数中,你正在做一些与我假设的等价的事情:
(defun f1 (prompt)
(format *query-io* "~a: " prompt)
(read-line))
此:
- 将提示写入
*query-io*
,这意味着在未来的某个时间,它可能出现在*query-io*
指向的任何位置 - 从CCD_ 6读取一行
- 返回读取该行的结果
因此,如果您调用此函数,它将从*standard-input*
读取一行,该行可能是终端,但可能不是。在调用format
之后的某个时间,*query-io*
上可能会出现一些输出,也可能指向终端。如果,则不能保证输出何时出现,甚至不能保证:例如,如果您将函数修改为:
(defun f1.1 (prompt)
(format *query-io* "~a: " prompt)
(clear-output *query-io*)
(read-line))
提示很可能永远不会出现。
如果你没有明确地说"现在就写",那么写入流的函数何时实际出现输出取决于很多因素:
- 流指向什么
- 如果有缓冲区
- 缓冲区有多大
- 缓冲区有多满
- 你后来是否在流上调用了
clear-output
,以及clear-output
是否真的做了什么 - 是否后来用
:abort t
关闭了流,以及是否真的做了什么 - 木星卫星上巧克力的价格
在你的第二个函数中,事情基本上是一样的:
(defun f2 (prompt)
(format *standard-output* "~a: " prompt)
(read-line))
这一次format
正在写入*standard-output*
,而不是*query-io*
,并且您再次从*standard-input*
读取一行。同样,format
的输出何时以及是否出现,取决于神。
所以你需要做的是
- 要清楚您正在使用的流
- 实际上,要求输出在您需要的时候出现,而不是稍后出现
特别是永远不要假设写入某个流的输出出现在任何给定点"单独"或"换行后",或类似的情况。
如果你想提示和阅读*query-io*
,你可以这样做:
(defun f3 (prompt)
(format *query-io* "~a: " prompt)
(finish-output *query-io*)
(read-line *query-io*))
如果您想在*standard-output*
上提示并从*standard-input*
读取,则:
(defun f4 (prompt)
(format *standard-output* "~a: " prompt)
(finish-output *standard-output*)
(read-line *standard-input*))
在最后一种情况下,您实际上可以忽略流(并使用t
表示format
),因为它们是默认值:但显式可能更好。
f3
可能更好,因为提示和阅读是*query-io*
的作用。