在sbcl repl中执行以下代码时,我得到变量test-cases的'未定义变量'警告,n。我在论坛上遇到了类似的问题,如果变量是setf / setq'ed而没有先定义,则会出现警告。但我已经使用defparameter定义了这些变量,但仍然收到了警告。
我注意到的一件事是,如果我没有在格式语句中引用变量,则不会发生警告。我也尝试过使用defvar。但它仍然在发出警告。是否有人可以帮助我理解为什么即使定义了变量,在用于法规时也会抛出警告?
(defun main ()
(defvar test-cases 10)
(defvar l 12)
(defvar n 13)
(format t "~a ~a ~a" test-cases l n))
; in: DEFUN MAIN
; (FORMAT T "~a ~a ~a" TEST-CASES L N)
;
; caught WARNING:
; undefined variable: N
;
; caught WARNING:
; undefined variable: TEST-CASES
;
; compilation unit finished
; Undefined variables:
; N TEST-CASES
; caught 2 WARNING conditions
WARNING: redefining COMMON-LISP-USER::MAIN in DEFUN
下面解释了为什么会出现错误,但请注意,很少需要从内部函数定义全局变量,大多数情况下,您将使用LET
的本地绑定。
这是一个简化的测试用例:
(defun foo () (defvar bar nil) bar)
当foo
正在编译时,bar
未定义(假设一个新的CL环境)。这就是编译器抱怨的原因。但是,如果调用foo
,则将声明变量(全局),然后返回其值。
对DEFVAR
的调用只有在执行时才对全局环境产生影响,或者在编译时它是顶级窗体时:
但是,下面描述的编译时副作用仅在它们显示为顶级表单时发生。
...
副作用:如果
defvar
或defparameter
表单显示为顶级表单,则编译器必须识别该名称已被声明为特殊名称。但是,它既不能评估初始值形式,也不能在编译时分配名为name的动态变量。
因此,在函数体内编译对defvar
的调用并不会将符号声明为特殊变量。