12.8 常量结构 (Constant Structure)
因为常量实际上是程序代码的一部分,所以我们也不应该修改他们,或者是不经意地写了自重写的代码。一个通过 quote
引用的列表是一个常量,所以一定要小心,不要修改被引用的列表的任何 cons
。比如,如果我们用下面的代码,来测试一个符号是不是算术运算符:
(defun arith-op (x)
(member x '(+ - * /)))
如果被测试的符号是算术运算符,它的返回值将至少一个被引用列表的一部分。如果我们修改了其返回值,
> (nconc (arith-op '*) '(as i t were))
(* / AS IT WERE)
那么我就会修改 arith-op
函数中的一个列表,从而改变了这个函数的功能:
> (arith-op 'as )
(AS IT WERE)
写一个返回常量结构的函数,并不一定是错误的。但当你考虑使用一个破坏性的操作是否安全的时候,你必须考虑到这一点。
有几个其它方法来实现 arith-op
,使其不返回被引用列表的部分。一般地,我们可以通过将其中的所有引用( quote
) 替换成 list
来确保安全,这使得它每次被调用都将返回一个新的列表:
(defun arith-op (x)
(member x (list '+ '- '* '/)))
这里,使用 list
是一种低效的解决方案,我们应该使用 find
来替代 member
:
(defun arith-op (x)
(find x '(+ - * /)))
这一节讨论的问题似乎只与列表有关,但实际上,这个问题存在于任何复杂的对象中:数组,字符串,结构,实例等。你不应该逐字地去修改程序的代码段。
即使你想写自修改程序,通过修改常量来实现并不是个好办法。编译器将常量编译成了代码,破坏性的操作可能修改它们的参数,但这些都是没有任何保证的事情。如果你想写自修改程序,正确的方法是使用闭包 (见 6.5 节)。
当前内容版权归 readthedocs 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 readthedocs .