得到'未定义的变量'警告,尽管它定义了

问题描述 投票:1回答:1

在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
common-lisp sbcl
1个回答
4
投票

下面解释了为什么会出现错误,但请注意,很少需要从内部函数定义全局变量,大多数情况下,您将使用LET的本地绑定。

这是一个简化的测试用例:

(defun foo () (defvar bar nil) bar)

foo正在编译时,bar未定义(假设一个新的CL环境)。这就是编译器抱怨的原因。但是,如果调用foo,则将声明变量(全局),然后返回其值。

DEFVAR的调用只有在执行时才对全局环境产生影响,或者在编译时它是顶级窗体时:

但是,下面描述的编译时副作用仅在它们显示为顶级表单时发生。

...

副作用:如果defvardefparameter表单显示为顶级表单,则编译器必须识别该名称已被声明为特殊名称。但是,它既不能评估初始值形式,也不能在编译时分配名为name的动态变量。

因此,在函数体内编译对defvar的调用并不会将符号声明为特殊变量。

© www.soinside.com 2019 - 2024. All rights reserved.