# 11.6 生成器（DONE）

&#x20;生成器（generatro）是一种潜在可能生成无限数据流的函数。生成器在调用时每次会生成一个值，抛出给调用者，然后将自己挂起，等待下一次的调用。

\[Macro] iter-defun name args \[doc] \[declare] \[interactive] body...

iter-defun 用来定义一个生成器函数。生成器函数和常规函数的函数签名没有什么区别，但是运行的方式会有些区别。常规函数在调用的时候会对函数体进行求值，但生成器函数不同。生成器函数会返回一个迭代器对象（iterator object）。该迭代器会运行 body 部分以生成一个值，在 iter-yield 或 iter-yield-from 处将该值返回给调用方，并暂停运行。之后某刻，

body 中可以包含任何Lisp代码，但是 iter-yield 和 iter-yield-from 不能在 unwind-protect 中使用。

\[Macro] iter-lambda args \[doc] \[interactive] body...

iter-lambda 生成一个匿名生成器函数，该生成器与常规 iter-defun 定义的生成器没有什么区别。

\[Macro] iter-yield value

该宏应该写在在生成器函数定义内。当该宏出现在生成器函数内部时，就指明当前生成器应当在此处暂停，并将 value 返回给 iter-next 处。 iter-yield 求值结果为下一次 iter-next 调用的 value 值。

\[Macro] iter-yield-from iterator

iter-yield-from 会抛出 iterator 生成的所有值，其求值结果为常规生成器函数生成的值。（while

使用生成器函数，首先要先正常调用一下，使其生成一个迭代器对象。迭代器是生成器的一种特殊实例。接下来我们需要使用 iter-next 从这个迭代器中取值。当迭代器中没有值返回时，iter-next 会抛出 iter-end-of-sequence condition 与迭代器的最后值。

需要注意的是，生成器函数的函数体仅在 iter-next 的调用下才会求值运行。对生成器函数的正常调用只会让其生成迭代器；你必须使用 iter-next 取驱动这个迭代器，从中取值。每次对生成器函数的常规调用都会生成一个不同的迭代器，这些迭代器的状态都是独立的。

\[Function] iter-next iterator value

从迭代器 iterator 中取出下一个值。若没有更多的值生成了（通常是因为生成器函数返回了），iter-next 会抛出 iter-end-of-sequence 条件；和这个条件一同返回的还有生成器函数返回的值。

value 会被传入迭代器 iterator，该值会成为 iter-yield 求值的结果。第一次 iter-next 调用时，value会被忽略，因为这时还在迭代器的生成器函数的顶部，还没有运行到 iter-yield 表达式。

\[Function] iter-close iterator

若迭代器 iterator 在 unwind-protect 的 bodyform 内被弃置了，而且无法获取，那么 Emacs 会在垃圾回收后运行 unwind 处理器。（需要注意的是，在 unwind-protect 内的 unwindforms 中使用 iter-yield 是不合法的。）为了让处理器在垃圾回收前运行，你需要使用 iter-close。

下面还有若干辅助函数，用来更简洁的使用迭代器：

\[Macro] iter-do (var iterator) body...

将 var 绑定到 iterator 生成的每个值，然后运行 body。

Common Lisp loop 包也提供了一些与迭代器一起协作的特性。这部分请查阅 Common Lisp Extensions 章的 “Loop Facility"部分。

下面的例子展示了一些使用迭代器时的重要原则。

```lisp
(require 'generator)
(iter-defun my-iter (x)
  (iter-yield (1+ (iter-yield (1+ x))))
   ;; 正常返回
  -1)
  
(let* ((iter (my-iter 5))
       (iter2 (my-iter 0)))
       ;; 打印 6
       (print (iter-next iter))
       ;; 打印 9
       (print (iter-next iter 8))
       ;; 打印 1; 这里 iter 和 iter2 的状态时分离独立的
       (print (iter-next iter2 nil))
       ;; 这里我们知道 iter 迭代序列已经到头了
       (condition-case x
           (iter-next iter)
         (iter-end-of-sequence
           ;; 打印 -1， 这里是my-iter 的常规返回值
           (print (cdr x)))))
```


---

# 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/kong-zhi-jie-gou/sheng-cheng-qi.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.
