19 lisp scope common-lisp literals
有人可以解释以下行为吗?具体来说,为什么函数每次都返回一个不同的列表?为什么每次调用函数时都没有some-list初始化'(0 0 0)?
(defun foo ()
(let ((some-list '(0 0 0)))
(incf (car some-list))
some-list))
Run Code Online (Sandbox Code Playgroud)
输出:
> (foo)
(1 0 0)
> (foo)
(2 0 0)
> (foo)
(3 0 0)
> (foo)
(4 0 0)
Run Code Online (Sandbox Code Playgroud)
谢谢!
编辑:
另外,假设我希望'(1 0 0)每次输出函数,推荐的实现此函数的方法是什么?
Vse*_*kin 25
'(0 0 0)是一个文字对象,它被假定为一个常量(虽然不受修改保护).所以你每次都有效地修改同一个对象.要在每个函数调用时创建不同的对象(list 0 0 0).
所以除非你知道,你正在做什么,你应该总是使用文字列表(比如'(0 0 0))作为常量.
gil*_*gan 11
另外,在sbcl REPL中定义此函数会出现以下警告:
caught WARNING:
Destructive function SB-KERNEL:%RPLACA called on constant data.
See also:
The ANSI Standard, Special Operator QUOTE
The ANSI Standard, Section 3.2.2.3
Run Code Online (Sandbox Code Playgroud)
这提供了对手头问题的良好暗示.
'(0 0 0)在代码中是文字数据.修改此数据具有未定义的行为.Common Lisp实现可能无法在运行时检测到它(除非数据放在某些只读存储空间中).但它可能会产生不良影响.
你会看到这些数据可能(通常是)在同一函数的各种调用中共享
其中一个更微妙的可能错误是:Common Lisp已经定义了各种优化,可以通过编译器来完成.例如,允许编译器重用数据:
例:
(let ((a '(1 2 3))
(b '(1 2 3)))
(list a b))
Run Code Online (Sandbox Code Playgroud)
在上面的代码段,编译器可以检测到的文字数据a和b是EQUAL.然后它可以使两个变量都指向相同的文字数据.修改它可能会起作用,但是从a和可以看到更改b.
简介:文字数据的修改是几个微妙错误的来源.尽可能避免使用它.然后,你需要利弊新的数据对象.Consing一般指新鲜的,新的数据结构在运行时的分配.