7

我有一个包含七个整数的列表,最初都是 0,我们称之为“数据”。在运行我的程序的过程中,我想定期将这些整数之一的值加一。在程序结束时,我打印数据。一切都很好,除了在程序的每次连续运行中,上次运行的所有数据值都被添加到本次运行的所有数据值中。我只想要这次运行的数据值。无论数据是类方法中的局部变量、类方法调用的单独函数中的局部变量还是类的槽,都会发生这种意外行为。无论我通过 incf 还是 (setf value (1+ value)) 增加数据的各个值,都会发生这种情况。当我重新加载程序时,数据会重置为全零,但是当我再次运行程序时,数据会再次添加上次运行的所有数据' s 数据到本次运行的数据。当我增加一个数据值时,我使用函数 nth ,其中 index 是另一个对象插槽的值。什么可能导致我的“数据”列表值的这种不受欢迎的持久性?

4

1 回答 1

17

Are you doing something like this:

CL-USER> (defun foo ()
           (let ((value '(1)))     ; '(1) is literal data
             (incf (car value))))
FOO
CL-USER> (foo)
2
CL-USER> (foo)
3
CL-USER> (foo)
4
CL-USER> (foo)
5

Quoted data is literal data; there's only one copy of it, and the consequences of modifying it are undefined. The behavior above is common, but you can't depend on it. Some compilers will give a warning when you do this. E.g., in SBCL:

CL-USER> (defun foo ()
           (let ((value '(1)))
             (incf (car value))))
; in: DEFUN FOO
;     (INCF (CAR VALUE))
; --> LET* 
; ==>
;   (SB-KERNEL:%RPLACA #:TMP1 #:NEW0)
; 
; 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
; 
; compilation unit finished
;   caught 1 WARNING condition
FOO

The relevant text from the HyperSpec on quote is:

The consequences are undefined if literal objects (including quoted objects) are destructively modified.

Create modifiable lists with, e.g., (list 1), not '(1). This is a common pitfall until you've encountered it. There are some other questions on StackOverflow that mention this issue. A very specific one is

but there are a bunch, too:

The same thing happens in Scheme, though the citations to the documentation are obviously different. For R5RS, the documentation is the following:

4.1.2 Literal expressions

… As noted in section 3.4, it is an error to alter a constant (i.e. the value of a literal expression) using a mutation procedure like set-car! or string-set!.

3.4 Storage model

… In many systems it is desirable for constants (i.e. the values of literal expressions) to reside in read-only-memory. To express this, it is convenient to imagine that every object that denotes locations is associated with a flag telling whether that object is mutable or immutable. In such systems literal constants and the strings returned by symbol->string are immutable objects, while all objects created by the other procedures listed in this report are mutable. It is an error to attempt to store a new value into a location that is denoted by an immutable object.

There are questions about this as well:

于 2013-09-13T15:55:01.810 回答