为什么在KEYWORD包中可以引用此前未定义的变量?
底层原因
KEYWORD是ANSI Common Lisp标准明确定义的特殊包,本身就被赋予了和普通用户包完全不同的符号查找、创建语义,这是关键字符号不需要预定义就能直接引用的核心前提。
普通包的符号引用逻辑是:当你引用包名:符号名格式的内容时,首先会校验对应包中是否已经存在对应的导入/导出符号,如果符号不存在会直接抛出未定义错误;而且普通符号默认没有值绑定,需要通过defvar/defparameter等语句手动绑定后才能作为变量取值,否则就会触发类似SBCL中The variable X is unbound的报错。
而KEYWORD包的符号查找走的是标准定制的特殊分支:只要你引用了KEYWORD:XXX格式的内容,哪怕该符号之前不存在,也不会触发报错,Lisp会自动完成符号的创建和初始化。
动态自动创建的实现逻辑
这个特性是在Lisp读取器(Reader)和包系统的底层逻辑中实现的,不属于普通用户态变量的管理范畴:
- 当Lisp读取器解析到以冒号开头的符号(比如
:XYZ)、或者显式带KEYWORD包前缀的符号(KEYWORD:XYZ)时,会先在KEYWORD包中查找对应名称的符号 - 如果查找不到,会自动执行三个操作:
- 在
KEYWORD包中创建对应名称的新符号 - 自动将该符号的
symbol-value绑定到符号本身,也就是说关键字永远是自身的值,所以你引用KEYWORD:XYZ的时候自然就能拿到:XYZ本身 - 自动将该符号标记为
KEYWORD包的导出符号,后续所有包都可以直接通过:XYZ的简写引用该符号
- 在
- 同时标准规定关键字是常量,无法修改它的值绑定,执行
(setf :XYZ 123)这类操作一定会抛出错误,这也是关键字和普通变量的核心差异之一。
内容的提问来源于stack exchange,提问作者Flux
相关产品推荐
相关产品推荐

