关键字与其他符号的区别
Rainer Joswig's answer 很好地描述了符号本身。不过,总而言之,每个符号都属于一个包。 p::foo(或p:foo,如果它是外部的)是包p 中的一个符号。如果您尝试将其评估为表单,您将获得其符号值,您可以使用 set 或 `(setf symbol-value) 设置:
CL-USER> (set 'foo 'bar)
BAR
CL-USER> foo
BAR
CL-USER> (setf (symbol-value 'foo) 'baz)
BAZ
CL-USER> foo
BAZ
有一个名为keyword 的特殊包。如果你愿意,你可以写keyword::foo,但是所有关键字包的符号都是外部的,所以你可以写keyword:foo。但是,由于它们非常常用,您甚至可以获得它们的特殊语法::foo。它们还具有您无法设置其值的特殊属性;他们的价值观就是他们自己:
CL-USER> :foo
:FOO
CL-USER> (symbol-value :bar)
:BAR
这就是使关键字符号与众不同的全部原因。
关键字和其他符号作为 lambda 列表中的关键字名称
可能更重要的是,默认情况下,它们被用作 lambda 列表中“关键字参数”的指示符。例如,
CL-USER> ((lambda (&key foo bar)
(list foo bar))
:bar 23 :foo 12)
(12 23)
可以看出关键字符号主要用于命名参数,
但我问自己是否无法使用
引用符号也一样?
lambda 列表的语法实际上允许您使用关键字参数进行更多自定义。一个常见的事情是指定默认值:
CL-USER> ((lambda (&key (foo 'default-foo) bar)
(list foo bar))
:bar 23)
(DEFAULT-FOO 23)
您还可以提供一个绑定到布尔值的变量名,指示是否指定了参数:
CL-USER> ((lambda (&key (foo 'default-foo foo-p) (bar 'default-bar bar-p))
(format t "~{~A:~7t~A~%~}"
(list 'foo foo
'foo-p foo-p
'bar bar
'bar-p bar-p)))
:bar 23)
FOO: DEFAULT-FOO
FOO-P: NIL
BAR: 23
BAR-P: T
不过,3.4.1 Ordinary Lambda Lists 的完整语法让我们可以做更多事情。这是
lambda-list::= (var*
[&optional {var | (var [init-form [supplied-p-parameter]])}*]
[&rest var]
[&key {var | ({var | (keyword-name var)} [init-form [supplied-p-parameter]])}* [&allow-other-keys]]
[&aux {var | (var [init-form])}*])
请注意,您可以指定keyword-name。它默认为关键字包中与var 同名的符号,但您实际上可以提供它并指定您自己的“关键字”。这可能很方便,例如,如果您想要一个描述性的关键字名称但不想要这么长的变量名称:
CL-USER> ((lambda (&key ((:home-directory dir)))
(list dir))
:home-directory "/home/me")
("/home/me")
您还可以使用它来指定不是关键字符号的关键字名称:
CL-USER> ((lambda (&key ((surprise surprise)))
(list surprise))
'surprise "hello world!")
("hello world!")
您也可以将两者结合起来:
CL-USER> ((lambda (&key ((hidden-parameter secret)))
(format t "the secret is ~A" secret))
'hidden-parameter 42)
the secret is 42
您也可以将其与默认值混合使用,但您现在可能明白了。