在 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 来工作—它取 CDR 的 CDR 的 CDR …
以下两个表达式产生相同的结果:
(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
)。它返回列表的长度。
而 n
是 current-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-ring
和 kill-ring-yank-pointer
都是 全局变量。这意味着 Emacs Lisp 中的任何表达式都可以访问它们。它们不像由 let
定义的局部变量或参数列表中指定的符号那样。局部变量只能在定义它们的 let
内部或在参数列表中指定它们的函数内访问(以及由它们调用的表达式内访问)。
(See let
避免混淆, 和
The defun
Macro.)