Common Lisp中in-package的参数类型、合法写法差异及常见问题解答
in-package 参数写法全解析 咱们先从HyperSpec的定义入手:in-package的参数name是string designator(字符串指示符),而且这个参数不被求值。string designator指的是能被转换成字符串的对象,包括字符串、各类符号(普通符号、关键字符号、未interned符号),这也是你测试的几种写法都有效的原因。下面逐个拆解它们的区别,再聊聊怎么选,最后解释带引号写法报错的问题。
几种合法写法的差异
(in-package my-package)
这里传递的是普通符号my-package。因为in-package参数不求值,所以直接取这个符号的名字(默认是大写的"MY-PACKAGE",除非你修改了*readtable-case*)来匹配包。需要注意:就算当前包里已经有同名符号,也不会影响结果——因为in-package只关心符号的名字,而非符号本身。(in-package :my-package)
这是关键字符号,属于全局的KEYWORD包,名字同样是"MY-PACKAGE"。关键字符号的优势是全局唯一,不会和任何用户包中的同名符号冲突,写法还简洁,是社区日常开发里最流行的选择。(in-package #:my-package)
这是未interned符号(uninterned symbol),它的名字也是"MY-PACKAGE",但不会被注册到当前包的符号表中。这种写法能避免污染当前包的符号空间,但日常开发中必要性不高,只有在你明确不想让当前包持有这个符号时才需要用。(in-package "MY-PACKAGE")
直接传递字符串,完全明确指定包名。这种写法最精确,尤其适合包名包含小写字母(需要配合*readtable-case*设置)或特殊字符的场景,不会受符号大小写规则的影响。
该选哪种写法?
- 优先推荐
:my-package:简洁、无冲突,是行业通用写法; - 如果需要精确控制包名(比如包名有特殊大小写),用字符串
"MY-PACKAGE"; - 普通符号
my-package也可以用,但要注意*readtable-case*的设置,避免符号名字和包名不匹配; - 未interned符号
#:my-package只在特殊场景下使用(比如临时引用包且不想污染当前符号表)。
为什么(in-package 'my-package)会报错?
核心原因是**in-package是宏,参数不被求值**:
当你写(in-package 'my-package)时,宏接收到的参数是'my-package,也就是(quote my-package)这个列表(cons cell),而不是符号my-package本身。而列表不属于string designator的范畴,所以会触发错误:
; compiling file "/path/to/my-program.lisp" (written 12 MAR 2021 01:23:45 AM):
; compiling (IN-PACKAGE (QUOTE MY-PACKAGE))
; file: /path/to/my-program.lisp
; in: IN-PACKAGE 'MY-PACKAGE
; (IN-PACKAGE 'MY-PACKAGE)
;
; caught ERROR:
; (during macroexpansion of (IN-PACKAGE 'MY-PACKAGE))
; 'MY-PACKAGE is not a string designator
而你测试的合法写法,都是直接传递string designator类型的对象(符号或字符串),而非表达式——这就是为什么关键字、未绑定符号合法,但带引号的写法不行的关键。
内容的提问来源于stack exchange,提问作者Flux




