为什么我的变量nodes
在vector-push-extend行中未定义?
(defun make_graph (strings)
(defparameter nodes (make-array 0))
(loop for x in strings do
(vector-push-extend (make-instance 'node :data x) nodes))
n)
答案 0 :(得分:4)
简短的回答是,您应该使用let
代替defparameter
来介绍您的变量。例如:
(defun make_graph (strings)
(let ((nodes (make-array 0)))
(loop for x in strings do
(vector-push-extend (make-instance 'node :data x) nodes))
;; your code says N here, but I assume that's a typo...
nodes))
defparameter
表单对于创建"特殊"非常有用。变量,有点类似于其他编程语言中的全局变量。 (存在一些差异,例如,defparameter
引入的特殊变量并非完全全局 - 相反,它们是动态范围的,可以let
绑定等...)
无论如何,let
表单将改为创建一个局部变量。
答案 1 :(得分:4)
DEFPARAMETER
用于顶层来定义全局特殊变量。
Toplevel为:
(defparameter *foo* 42)
仍处于顶层,因为PROGN
内的形式仍处于顶层(根据定义):
(progn
(defparameter *foo* 42)
(defparameter *bar* 32))
不在顶级:
(defun baz ()
(defparameter *foo* 42))
编译器不会将上一个表单识别为变量声明。但是当一个人调用(baz)
并且函数正在运行时,就会定义并初始化变量。
编译器无法识别DEFPARAMETER的非顶层使用,但在运行时它将创建一个特殊的全局变量。
(defun make_graph (strings)
(defparameter nodes (make-array 0))
(loop for x in strings do
(vector-push-extend (make-instance 'node :data x) nodes))
n)
编译器发出警告:
;;;*** Warning in MAKE_GRAPH: NODES assumed special
;;;*** Warning in MAKE_GRAPH: N assumed special
因此,在上面的代码中,编译器不会将nodes
识别为已定义的变量,如果它尚未在其他地方定义的话。函数中{em> use 的nodes
会产生警告。
代码仍然可以工作,因为在运行时创建并初始化变量 - 但是对于每个函数调用。一遍又一遍。这个编译器还假设nodes
就是这样:某种特殊变量。对于所有编译器,我仍然不会指望它。
n
也未在任何地方定义。
备注强>:
引入本地词汇变量的正确方法是使用LET
和LET*
(和其他绑定形式)
使用DEFPARAMETER
作为顶层形式。当它不是一种顶级形式时,这是不寻常的。通常作者会犯错误。