确定元素

if 表达式的 else 部分中,除了执行其他动作外,当 kill 环中有内容且 do-not-move 的值为 nil 时,if 表达式的 else 部分会将 kill-ring-yank-pointer 的值设置为 ARGth-kill-element

代码如下:

(nthcdr (mod (- n (length kill-ring-yank-pointer))
             (length kill-ring))
        kill-ring)))

这需要一些解释。除非不打算移动指针,current-kill 函数会改变 kill-ring-yank-pointer 指向的位置。 这就是 (setq kill-ring-yank-pointer ARGth-kill-element)) 表达式的作用。 显然,ARGth-kill-element 被设置为与 kill 环的某个 CDR 相等,使用了在前面一节中描述的 nthcdr 函数。 (See copy-region-as-kill。) 它是如何实现的呢?

正如我们之前所看到的 (see nthcdr),nthcdr 函数通过反复取列表的 CDR 来工作—它取 CDRCDRCDR

以下两个表达式产生相同的结果:

(setq kill-ring-yank-pointer (cdr kill-ring))

(setq kill-ring-yank-pointer (nthcdr 1 kill-ring))

然而,nthcdr 表达式更加复杂。它使用 mod 函数来确定要选择哪个 CDR

(记得先看内部函数;事实上,我们将不得不深入了解 mod。)

mod 函数返回其第一个参数对第二个参数取模的值;换句话说,它返回第一个参数除以第二个参数后的余数。返回值与第二个参数具有相同的符号。

因此,

(mod 12 4)
  ⇒ 0  ;; 因为没有余数
(mod 13 4)
  ⇒ 1

在这种情况下,第一个参数通常小于第二个参数。这没问题。

(mod 0 4)
  ⇒ 0
(mod 1 4)
  ⇒ 1

我们可以猜测 - 函数的作用。它类似于 +,但是执行减法而不是加法;- 函数从其第一个参数中减去第二个参数。此外,我们已经知道 length 函数的作用 (see 查找列表的长度:length)。它返回列表的长度。

ncurrent-kill 函数的必需参数的名称。

因此,当 nthcdr 的第一个参数为零时,nthcdr 表达式返回整个列表,如下所示:

;; kill-ring-yank-pointer 和 kill-ring 的长度均为四
;; 而 (mod (- 0 4) 4) 的结果为 0
(nthcdr (mod (- 0 4) 4)
        '("fourth line of text"
          "third line"
          "second piece of text"
          "first some text"))

current-kill 函数的第一个参数为一时,nthcdr 表达式返回不包含其第一个元素的列表。

(nthcdr (mod (- 1 4) 4)
        '("fourth line of text"
          "third line"
          "second piece of text"
          "first some text"))

顺便说一下,kill-ringkill-ring-yank-pointer 都是 全局变量。这意味着 Emacs Lisp 中的任何表达式都可以访问它们。它们不像由 let 定义的局部变量或参数列表中指定的符号那样。局部变量只能在定义它们的 let 内部或在参数列表中指定它们的函数内访问(以及由它们调用的表达式内访问)。

(See let 避免混淆, 和 The defun Macro.)