# 2.9 可变性

一些 Lisp 对象永远不应该改变其内容。例如，Lisp 表达式`"aaa"`生成一个字符串，但您不应更改其内容。有些对象是不可变的；例如，尽管您可以通过计算 1 来创建一个新数字，但 Lisp 不提供更改现有数字值的操作。

其他 Lisp 对象是*可变的*：通过具有副作用的破坏性操作来更改它们的值是安全且被允许的。例如，可以通过将标记移动到其他位置来更改现有标记。

数字永远是不可变的，并且所有标记都是可变的。此外，某些类型具有若干成员，其中一些成员是可变的，而另一些则不是。这些类型包括点对、向量和字符串。例如，虽然`"cons"`和`(symbol-name 'cons)`都生成不可变的字符串，但`(copy-sequence "cons")`和 `(make-string 3 ?a)`都生成可以通过 aset 改变的可变字符串。

如果可变对象是被求值的表达式的一部分，那它就不再是可变的。例如：

```
(let* ((x (list 0.5))
       (y (eval (list 'quote x))))
  (setcar x 1.5) ;; 程序不应该做这样的事情
  y)
```

尽管该列表`(0.5)`在创建时是可变的，但它不应通过 `setcar` 更改，因为它已提供给`eval`用于求值。 相反的情况则不会发生：不可变的对象在此之后永远不会变得可变。

如果程序试图更改不可变对象，则结果行为是未定义的：Lisp 解释器可能会抛出错误信号，或者它可能会崩溃或出现其他方式无法预测的反应。[2](https://www.gnu.org/software/emacs/manual/html_node/elisp/Mutability.html#FOOT2)

当类似的常量作为程序的一部分出现时，Lisp 解释器可能会通过重用现有的常量或其组件来节省时间或空间。例如，在例子`(eq "abc" "abc")`中，如果解释器只创建一个字符串常量的实例`"abc"`返回 `t`，如果它创建两个实例，则返回`nil`。应该编写这样的 Lisp 程序，以便无论是否使用这种优化，它们都可以工作。

**脚注**

**(2)**

这是为 Common Lisp 和 C 等语言指定的常量行为，这与 JavaScript 和 Python 等语言不同，如果程序试图更改不可变对象，则需要解释器来发出错误信号。理想情况下，Emacs Lisp 解释器将会在后续版本中覆盖这一问题。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://emacs-lisp.ivory.cafe/lisp-shu-ju-lei-xing/2.9-ke-bian-xing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
