134

我从很久以前就对其他 Lisp(尤其是 Scheme)有了初步的了解。最近我一直在阅读有关Clojure的内容。我看到它既有“符号”又有“关键字”。我熟悉的符号,但不是关键字。

其他 Lips 有关键字吗?除了具有不同的符号(即:冒号)之外,关键字与符号有何不同?

4

6 回答 6

144

这是关键字和符号的Clojure 文档

关键字是对自身进行评估的符号标识符。他们提供非常快速的平等测试......

符号是通常用来指代其他事物的标识符。它们可以在程序形式中用于引用函数参数、let 绑定、类名和全局变量...

关键字通常用作轻量级的“常量字符串”,例如用于哈希映射的键或多方法的调度值。符号通常用于命名变量和函数,除了在宏等中之外,直接将它们作为对象操作不太常见。但是没有什么能阻止您在使用关键字的任何地方使用符号(如果您不介意一直引用它们)。

Keyword.java查看差异的最简单方法是阅读Symbol.javaClojure 源代码。有一些明显的实现差异。例如,Clojure 中的符号可以有元数据,而关键字则不能。

除了单冒号语法之外,您还可以使用双冒号来制作命名空间限定关键字。

user> :foo
:foo
user> ::foo
:user/foo

Common Lisp 有关键字,Ruby 和其他语言也有。当然,它们在这些语言中略有不同。Common Lisp 关键字和 Clojure 关键字之间的一些区别:

  1. Clojure 中的关键字不是符号。

    user> (symbol? :foo)  
    false
    
  2. 关键字不属于任何命名空间,除非您特别限定它们:

    user> (namespace :foo)
    nil
    user> (namespace ::foo)
    "user"
    

(感谢Rainer Joswig给了我一些可以看的东西的想法。)

于 2009-10-06T19:52:21.263 回答
30

Common Lisp有关键字符号。

关键字也是符号。

(symbolp ':foo) -> T

是什么让关键字特别:

  • :foo 被 Common Lisp 阅读器解析为符号关键字::foo
  • 关键字对自己进行评估: :foo -> :foo
  • 关键字符号的主包是 KEYWORD 包:keyword:foo -> :foo
  • 关键字是从包 KEYWORD 中导出的
  • 关键字是常量,不允许分配不同的值

否则关键字是普通符号。因此关键字可以命名函数或具有属性列表。

请记住:在 Common Lisp 中,符号属于一个包。这可以写成:

  • foo,当符号在当前包中可访问时
  • foo:bar,当符号 FOO 从包 BAR 导出时
  • foo::bar,当符号 FOO 在包 BAR 中时

对于关键字符号,这意味着:foo、keyword:foo 和keyword::foo 都是相同的符号。因此通常不使用后两种符号。

所以 :foo 只是被解析为在包 KEYWORD 中,假设在符号名称之前没有给出包名称意味着默认情况下是 KEYWORD 包。

于 2009-10-06T19:53:17.943 回答
6

关键字是对自身进行评估的符号,因此您不必记住引用它们。

于 2009-10-06T19:25:38.030 回答
5

:keywords 也被许多集合特别对待,允许一些非常方便的语法。

(:user-id (get-users-map))

是相同的

((get-users-map) :user-id)

这让事情变得更加灵活

于 2009-10-06T21:35:48.470 回答
4

对于关键字,在第一次构造关键字时计算并缓存哈希值。将关键字查找为散列键时,它只返回预先计算的散列值。对于字符串和符号,每次查找时都会重新计算哈希值。

为什么相同命名的关键字总是相同的,它们包含自己的哈希值。由于地图和集合中的搜索是由散列键组成的,因此在大量搜索的情况下,而不是在搜索本身中,这会带来更好的搜索效率。

于 2015-07-19T16:22:13.973 回答
-1

关键字是全局的,符号不是

这个例子是用 JavaScript 编写的,但我希望它有助于传达这一点。

const foo = Symbol.for(":foo") // this will create a keyword
const foo2 = Symbol.for(":foo") // this will return the same keyword
const foo3 = Symbol(":foo") // this will create a new symbol
foo === foo2 // true
foo2 === foo3 // false

当您使用该函数构造符号时,Symbol您每次都会得到一个不同的/私有符号。当您通过该函数请求符号时Symbol.for,您每次都会返回相同的符号。

(println :foo) ; Clojure
System.out.println(RT.keyword(null, "foo")) // Java
console.log(System.for(":foo")) // JavaScript

这些都是一样的。


函数参数名称是本地的。即不是关键字。

(def foo (fn [x] (println x))) ; x is a symbol
(def bar (fn [x] (println x))) ; not the same x (different symbol)
于 2019-10-03T16:12:20.043 回答