Ant*_*ana 4 variables reference common-lisp variable-assignment let
setf
when 与 结合的行为let
让我感到困惑。在这里,setf
不会更改列表中的第二个值。
(defun to-temp-field (lst)
(let ((old-value (nth 2 lst))
(new-value 'hello))
(progn
(setf old-value new-value)
lst)))
Run Code Online (Sandbox Code Playgroud)
但如果我不这样做let
,它会改变:
(defun to-temp-field (lst)
(let ((new-value 'hello))
(progn
(setf (nth 2 lst) new-value)
lst)))
Run Code Online (Sandbox Code Playgroud)
是什么导致了这种行为?
setf
接受一个位置和一个值,或多个位置/值对,并将位置的值更改为新值。
第一个代码示例old-value
是绑定在表单内的词法变量let
。词法变量是位置,因此调用将设置to(setf old-value new-value)
的值。old-value
new-value
函数形式也可以是地方,并且nth
是一个可以指定地点的函数。在第二个代码示例中,调用(setf (nth 2 lst) new-value)
将 place 的值设置(nth 2 lst)
为 value new-value
。
old-value
因此,在第一个示例中,词法变量place被更新。但在第二个示例中,表单(nth 2 lst)
是一个位置,并且该表单求值的对象(列表的元素lst
)被更新。
需要明确的是:地点不是一种价值,而是一种形式。
With(let ((old-value (nth 2 lst)) ;;...))
old-value
绑定到表单计算的值(nth 2 lst)
。但随着(setf (nth 2 lst) new-value)
形式被解释为一个地方。 其工作原理相同:是一种形式,也是一个地方。这里,变量已被 let-bound 绑定到表单 的值,并且通过改变 的绑定,通过调用中的赋值来替换该值。结果,该地方的价值发生了变化。(nth 2 lst)
(setf old-value new-value)
old-value
old-value
(nth 2 lst)
setf
old-value
old-value
有几点需要注意:
第二个示例更新了 的第三个元素,lst
因为列表在 Common Lisp 中是零索引的。
由于表单的主体是隐式的,因此不需要progn
内部的表单。let
let
progn
尝试修改文字会导致 Common Lisp 中出现未定义的行为,因此您不应该使用这样的带引号列表来调用第二个函数:(to-temp-field '(1 2 3))
或使用绑定到列表文字的变量,而是像这样:(to-temp-field (list 1 2 3))
或使用绑定到 a 的变量以其他方式构建的列表。