【发布时间】:2021-12-24 13:31:21
【问题描述】:
我在 SBCL 2.0.1 中试过这个:
(let ((s "Tom's house"))
(setf (subseq s 0 5) "Cat")
s)
我收到警告:
; in: LET ((S "Tom's house"))
; (SETF (SUBSEQ S 0 5) "Cat")
; --> LET*
; ==>
; (REPLACE #:SEQUENCE #:NEW1 :START1 0 :END1 5)
;
; caught WARNING:
; Destructive function REPLACE called on constant data: "Tom's house"
; See also:
; The ANSI Standard, Special Operator QUOTE
; The ANSI Standard, Section 3.2.2.3
;
; compilation unit finished
; caught 1 WARNING condition
但是当我尝试下面的代码时,我没有收到任何警告或错误。为什么我可以修改使用defparameter(或defvar)定义的字符串,但不能修改使用let定义的字符串?
(defparameter *s* "Tom's house")
(setf (subseq *s* 0 3) "Cat")
【问题讨论】:
-
编译文件时可能会出现这样的警告。似乎没有特定原因不发出警告,只是缺少此功能。
-
@RainerJoswig 在 Common Lisp 中是否完全不允许修改字符串?
-
这是不允许的。您可以修改在运行时创建的字符串。但是对于文字字符串(嵌入在源代码中的字符串),修改它们的效果在可移植的 Common Lisp 中是未定义的。例如,如果您有两个具有相同内容的字符串的 DEFPARAMETER 表单,那么编译器可能会优化空间并仅分配一个字符串 -> 为两个变量重用此字符串。然后修改一个字符串会看到两个不同变量的效果。另一个影响可能是编译器在只读内存中分配代码(以及它的数据)。
-
这种只读内存分配是不正常的,但在一些较新的系统上,这实际上可能更常见:ARM 上的 Apple iOS 可能不允许代码修改(这也是为什么 iOS 上的 Common Lisp 编译器不能允许在运行时创建/加载代码),最新的 macOS 也有类似的功能。
-
“如果文字对象(包括引用对象)被破坏性修改,后果是不确定的”在quote的定义中更合适
标签: common-lisp