为何SBCL中defparameter定义的字符串可修改而let定义的不行?
回答
ANSI Common Lisp标准明确规定:直接写在代码中的字面量字符串属于常量数据,对常量数据执行破坏性修改的行为是未定义的,SBCL的警告正是在提示你触发了这个违规操作。
两种写法的差异是SBCL的实现特性导致的:
- let绑定的场景:你直接把编译期的只读字面量
"Tom's house"绑定到了变量s,修改操作会直接作用在只读常量上,所以编译器在编译阶段就检测到了这个风险,抛出了对应的警告。 - defparameter/defvar的场景:这两个是顶层特殊变量定义操作,SBCL对顶层绑定的字面量做了默认处理,会自动复制一份运行期可写的字符串副本,而不是直接使用编译期的只读常量,所以你修改的是可写副本,不会触发警告也不会报错。
注意事项
这个自动复制的行为是SBCL特有的实现逻辑,不是Common Lisp的通用标准,不要依赖这个特性写代码。如果需要确保字符串可修改,不管用哪种绑定方式,都显式调用copy-seq复制字面量,安全写法如下:
;; let 场景安全写法 (let ((s (copy-seq "Tom's house"))) (setf (subseq s 0 5) "Cat") s) ;; 兼容所有Common Lisp实现的defparameter写法 (defparameter *s* (copy-seq "Tom's house")) (setf (subseq *s* 0 3) "Cat")
内容的提问来源于stack exchange,提问作者Flux
相关产品推荐
相关产品推荐

