在此站点:http://www.gigamonkeys.com/book/practical-a-simple-database.html,用户输入功能如下所示:
(defun prompt-read (prompt)
(format *query-io* "~%~a: " prompt)
(force-output *query-io*)
(read-line *query-io*))
与以下更简单的形式相比,上述功能是否有任何主要优点:
(defun prompt-read2 (prompt)
(format t "~%~a: " prompt)
(setf answer (read-line)))
建议始终始终使用force-output
和*query-io*
吗?
答案 0 :(得分:4)
设置这样的全局变量的答案是不好的。你应该只是回答答案,让调用者用它做你想做的事。如果你使用特殊(〜全局)变量,你应该在名称(*ANSWER*
而不是ANSWER
)周围添加星号。
FORCE-OUTPUT
以确保用户在必须回答之前实际看到提示。如果我在终端中使用SBCL运行第二个版本,程序就会冻结等待输入而不说任何内容。
*QUERY-IO*
来查询用户的内容,因为某些环境可能希望以不同于其他输出的方式处理。例如,有人可能会为您的程序编写一个GUI包装器,将查询转换为图形对话框。或者他们可能希望将其作为脚本的一部分运行,从字符串提供输入。
(defun prompt-read (prompt)
(format *query-io* "~%~a: " prompt)
(force-output *query-io*)
(read-line *query-io*))
(defun hello ()
(format t "~&Hello ~a!~%" (prompt-read "What's your name")))
(defmacro with-input ((input) &body body)
`(let ((*query-io* (make-two-way-stream (make-string-input-stream ,input)
(make-string-output-stream))))
,@body))
(defun test ()
(with-input ("jkiiski")
(hello))
(with-input ("rnso")
(hello)))
(test)
; Hello jkiiski!
; Hello rnso!
修改强>
使用SBCL灰色流的更复杂的示例。
(defclass foo-stream (sb-gray:fundamental-character-input-stream)
((output-input-script :initarg :script :accessor foo-stream-script)
(output-stream :initarg :out :accessor foo-stream-out)
(current-input :initform nil :accessor foo-stream-current-input)))
(defmethod sb-gray:stream-read-char ((stream foo-stream))
(with-accessors ((input foo-stream-current-input)
(out foo-stream-out)
(script foo-stream-script)) stream
(when (or (null input)
(not (listen input)))
(let ((output (string-trim '(#\space #\newline)
(get-output-stream-string out))))
(setf input (make-string-input-stream
(format nil "~a~%"
(cdr (assoc output script :test #'string=)))))))
(read-char input)))
(defun prompt-read (prompt)
(format *query-io* "~%~a: " prompt)
(force-output *query-io*)
(read-line *query-io*))
(defun hello ()
(format t "~&Hello ~a!~%" (prompt-read "What's your name"))
(format t "~&I'm ~a too!" (prompt-read "How are you"))
(format t "~&~a~%" (if (string-equal (prompt-read
"Do you want to delete all your files")
"yes")
"Deleting all files... (not really)"
"Not deleting anything.")))
(defmacro with-input-script ((script) &body body)
(let ((out-sym (gensym "out")))
`(let* ((,out-sym (make-string-output-stream))
(*query-io* (make-two-way-stream
(make-instance 'foo-stream
:out ,out-sym
:script ,script)
,out-sym)))
,@body)))
(defun test ()
(with-input-script ('(("What's your name:" . "jkiiski")
("How are you:" . "great")
("Do you want to delete all your files:" . "No")))
(hello))
(with-input-script ('(("What's your name:" . "Foo Bar")
("How are you:" . "fine")
("Do you want to delete all your files:" . "Yes")))
(hello)))
(test)
; Hello jkiiski!
; I'm great too!
; Not deleting anything.
; Hello Foo Bar!
; I'm fine too!
; Deleting all files... (not really)
答案 1 :(得分:2)
是的,你的代码很容易,但第一个更清楚你在做什么:
* query-io *是一个全局变量(由于全局变量的*命名约定,你可以告诉它)包含输入流 连接到终端。 prompt-read的返回值将是 最后一个表单的值,对READ-LINE的调用,返回 它读取的字符串(没有尾随换行符。)
这就是他们所说的* query-io *
关于你可以放在那里的溪流如下:
大多数其他I / O函数也接受T和NIL作为流指示符 但具有不同的含义:作为流指示符,T表示 双向流* TERMINAL-IO *,而NIL指定 * STANDARD-OUTPUT *作为输出流,* STANDARD-INPUT *作为输入流
在这种情况下,它似乎只指向* standard-input *而不指向双向流t