# 19.4 输出流

输出流指明了处理输出字符的方式。绝大多数的输出函数会接受一个输出流作为可选参数。下面列举了可能作为输出流的类型：

缓冲区 buffer

输出字符会被插入到 buffer 的位点处。位点会始终处于插入字符的前面。

记号 marker

输出字符会被插入到记号 marker 所在的缓冲区的记号位置。记号marker 会始终处于插入字符的前面。若输出为 marker，那么将不会对缓冲区内的位点的值有任何副作用。而且这种插入并不会改变位点（有个例外，若marker在位点的前面，那么位点的位置会发生改变）。

函数 function

输出字符会被作为参数传递给 function，其中该function需要将字符们储存起来。该函数被调用时，会传入单个字符作为参数，调用的次数取决于输出的字符数。该函数需要自行储存字符，如果你需要这么做。

t

输出字符会被在回显区域显示。如果 Emacs 在批处理模式下运行（查阅 批处理 模式），此时输出流会模式使用标准输出。

nil

nil 指明使用变量 standard-output 变量的值作为输出流；其值为默认输出流，而且必须为非 nil

symbol

Emacs 会查找符号 symbol 的函数定义，并将该定义作为输出流。

大多数合法的输出流作为输入流使用同样合法。其中重要的地方在于思考如何使用 Lisp 对象，而不是对象类型。

这里有一个使用缓冲区 buffer 作为输出流的例子。位点初始化在单词 "the" 中 "h" 之前。插入结束后，位点仍然在 "h" 之前。

```
---------- Buffer: foo ----------
This is t∗he contents of foo.
---------- Buffer: foo ----------

(print "This is the output" (get-buffer "foo"))
     ⇒ "This is the output"

---------- Buffer: foo ----------
This is t
"This is the output"
∗he contents of foo.
---------- Buffer: foo ----------
```

下面这个例子，我们使用记号作为输出流。初始化时，marker在缓冲区foo内，并在 单词 "the" 的 "t" 和 "h" 之间。在输出完毕后，记号仍在插入文本的前方，依然在"h"之前。注意，位点的位置，并不会发生变化。

```
---------- Buffer: foo ----------
This is the ∗output
---------- Buffer: foo ----------

(setq m (copy-marker 10))
     ⇒ #<marker at 10 in foo>

(print "More output for foo." m)
     ⇒ "More output for foo."

---------- Buffer: foo ----------
This is t
"More output for foo."
he ∗output
---------- Buffer: foo ----------

m
     ⇒ #<marker at 34 in foo>
```

下面这个例子使用了回显区域作为输出流

```
(print "Echo Area output" t)
     ⇒ "Echo Area output"
---------- Echo Area ----------
"Echo Area output"
---------- Echo Area ----------
```

最后，我们使用一个函数作为输出流。函数 eat-output 会将每个输出字符作为参数，然后对其使用 cons 加入到列表 last-output 中（详情查阅 构建列表）。最后，列表中会包含所有输出字符，不过顺序是反过来的。

```
(setq last-output nil)
     ⇒ nil

(defun eat-output (c)
  (setq last-output (cons c last-output)))
     ⇒ eat-output

(print "This is the output" #'eat-output)
     ⇒ "This is the output"

last-output
     ⇒ (10 34 116 117 112 116 117 111 32 101 104
    116 32 115 105 32 115 105 104 84 34 10)

```

现在我们可以将列表反序，再打印出来：

```
(concat (nreverse last-output))
     ⇒ "
\"This is the output\"
"
```

调用函数 concat 会自动将 列表list 转换为 字符串string，这样方便我们检查输出。

Function: external-debugging-output character

调试程序时，将这个函数作为输出流会非常有用。这个函数会将字符写到标准输出流中。

举个例子

```
(print "This is the output" #'external-debugging-output)
-| This is the output
⇒ "This is the output"
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://emacs-lisp.ivory.cafe/du-qu-he-da-yin-lisp-dui-xiang/19.4-shu-chu-liu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
