dolist

例如,假设你想反转一个列表, 让 “第一个” “第二个” “第三个” 变为 “第三个” “第二个” “第一个”。

实际使用中,你会直接用 reverse 函数,如下:

(setq animals '(gazelle giraffe lion tiger))

(reverse animals)

下面是用 while 循环实现列表反转的方式:

(setq animals '(gazelle giraffe lion tiger))

(defun reverse-list-with-while (list)
  "Using while, reverse the order of LIST."
  (let (value)  ; make sure list starts empty
    (while list
      (setq value (cons (car list) value))
      (setq list (cdr list)))
    value))

(reverse-list-with-while animals)

下面是使用 dolist 宏的写法:

(setq animals '(gazelle giraffe lion tiger))

(defun reverse-list-with-dolist (list)
  "Using dolist, reverse the order of LIST."
  (let (value)  ; make sure list starts empty
    (dolist (element list value)
      (setq value (cons element value)))))

(reverse-list-with-dolist animals)

在 Info 中,你可以将光标放在每个表达式的右括号后, 输入 C-x C-e;每种情况都应在回显区看到:

(tiger lion giraffe gazelle)

对于本例,显然已有的 reverse 函数是最佳选择。 while 循环和我们第一个示例类似(see A while Loop and a List)。 while 首先检查列表是否有元素; 如果有,就通过将列表第一个元素添加到现有列表(循环第一次迭代时为 nil) 来构造新列表。由于第二个元素被追加到第一个元素前面, 第三个被追加到第二个前面,列表就被反转了。

在使用 while 循环的表达式中, (setq list (cdr list)) 会缩短列表, 使 while 循环最终停止。 同时,它在每次循环中创建一个更短的新列表, 为 cons 表达式提供新的第一个元素。

dolist 表达式的作用与 while 非常相似, 区别在于 dolist 宏自动完成了编写 while 时需要手动做的部分工作。

while 循环一样,dolist 会进行循环。 不同之处在于,它每次循环都会自动缩短列表 — 自行取列表 CDR — 并自动将每个更短列表的 CAR 绑定到它的第一个参数。

在示例中,每个更短列表的 CAR 用符号 ‘element’ 表示, 列表本身叫作 ‘list’,返回值叫作 ‘value’。 dolist 表达式的其余部分是循环体。

dolist 表达式将每个更短列表的 CAR 绑定到 element, 然后执行表达式体,并重复循环。 结果由 value 返回。