如何解决修改 Lisp 中结构域/槽的副本
我正在尝试修改结构字段的副本。我尝试使用 copY-TREE
无济于事。这是我的代码:
(defstruct scenario
(board '() :type list)
(letters "" :type string)
(blank-char #\- :type character))
(defparameter *scen-1*
(make-scenario
:board (string->board "cat---|a-----|b-----" #\|)))
在SETF
之前:
(print *scen-1*)
#S(SCENARIO
:BOARD ("CAT---" "A-----" "B-----")
:LETTERS ""
:BLANK-CHAR #\-)
当我尝试使用 copY-TREE
修改电路板的副本时,它会修改原始电路板。
(let ((board (copy-tree (scenario-board *scen-1*))))
(setf (subseq (nth 1 board) 0 2) "GG"))
(print *scen-1*)
#S(SCENARIO
:BOARD ("CAT---" "GG----" "B-----")
:LETTERS ""
:BLANK-CHAR #\-)
*scen-1*
应该保持不变。
如何修改 BOARD
字段的副本,而不是原始字段?谢谢!
解决方法
问题是 COPY-TREE
复制了列表结构,而不是列表的元素。此处实际上并不需要 COPY-TREE
,因为要复制的列表是扁平的。
一种解决方法是编写一个函数,用另一个字符串中的字符替换一个字符串副本中的字符,然后在原始 board
的副本中替换所需的 board
元素。这是一个执行子字符串替换的函数:
;;; Writes the characters from NEW to OLD starting from START.
(defun replace-substring (old start new)
(let ((result (copy-seq old)))
(loop for replacement across new
for i from start below (+ start (length new))
do (setf (elt result i) replacement)
finally (return result))))
这是一个函数,它通过更新一个字符串元素的copy来更新 board
字段的copy:
;;; Creates a copy of the BOARD field with the Nth string replaced
;;; by a copy which has had the characters starting from POS
;;; replaced by the characters from NEW.
(defun update-board (board n pos new)
(let ((new-board (copy-list board))
(new-seq (replace-substring (nth n board) pos new)))
(setf (nth n new-board) new-seq)
new-board))
示例交互:
CL-USER> *scen-1*
#S(SCENARIO :BOARD ("cat---" "a-----" "b-----") :LETTERS "" :BLANK-CHAR #\-)
CL-USER> (update-board (scenario-board *scen-1*) 1 0 "gg")
("cat---" "gg----" "b-----")
CL-USER> *scen-1*
#S(SCENARIO :BOARD ("cat---" "a-----" "b-----") :LETTERS "" :BLANK-CHAR #\-)
,
作为上述答案的替代方案,我发现 MAPCAR
和 COPY-SEQ
可用于执行字符串列表的“深度复制”。
(let ((board (mapcar #'copy-seq (scenario-board *scen-1*))))
etc
这也能解决问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。