为何结合let使用setf时无法修改列表元素?
为什么setf结合let绑定局部变量时无法修改列表元素?
咱们直接说核心原因:
第一个代码的问题
你用let绑定old-value的时候,(nth 2 lst)返回的是列表第三个元素的当前值,这个值被拷贝到了局部变量old-value里。之后执行(setf old-value new-value),只是把这个局部变量的内容改成了new-value,完全没碰原列表的元素——相当于你把抽屉里的东西拿出来放在桌上,改了桌上的东西,抽屉里的原物当然没变。
对应的错误代码:
(defun to-temp-field (lst) (let ((old-value (nth 2 lst)) (new-value 'hello)) (progn (setf old-value new-value) lst)))
第二个代码能生效的原因
而(setf (nth 2 lst) new-value)里的(nth 2 lst)不是单纯的值,Lisp里把它叫做位置(place)。setf能识别这种位置形式,它会直接找到原列表中第三个元素的存储位置,把new-value放进去——相当于直接伸手到抽屉里替换里面的东西,原列表自然就被修改了。
对应的正确代码:
(defun to-temp-field (lst) (let ((new-value 'hello)) (progn (setf (nth 2 lst) new-value) lst)))
简单总结:
setf操作局部变量时,只是改变变量自身的绑定,和原始数据结构无关setf操作像(nth i lst)这种位置形式时,才会直接修改原始数据结构里的内容
内容的提问来源于stack exchange,提问作者Antonio Solana
相关产品推荐
相关产品推荐

