# 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"
```
