我对其他Lisps(特别是Scheme)有一些了解。最近我一直在阅读Clojure方面的内容。我看到它既有“符号”又有“关键字”。我熟悉符号,但不熟悉关键字。
其他Lisps是否有关键字?除了使用不同的符号表示(即冒号),关键字与符号有何不同?
这里是关于Keywords和Symbols的Clojure文档。
Keywords是符号标识符,它们被求值为它们自己。它们提供非常快速的相等性测试...
Symbols是标识符,通常用于引用其他事物。它们可以在程序表单中用于引用函数参数、let绑定、类名和全局变量...
Keywords通常被用作轻量级的“常量字符串”,例如哈希映射的键或多方法的调度值。Symbols通常用于命名变量和函数,除了在宏等方面直接处理它们以外,不太常见将其用作对象进行操作。但如果您不介意一直加引号,完全可以在使用Keyword的地方都使用Symbol。
最简单的区别方法是阅读Clojure源代码中的Keyword.java
和Symbol.java
。有一些明显的实现差异。例如,在Clojure中,Symbol可以具有元数据,而Keyword则不行。
除了单冒号语法外,您还可以使用双冒号来制作命名空间限定的keyword。
user> :foo
:foo
user> ::foo
:user/foo
Common Lisp、Ruby和其他语言都有关键字。当然,它们在这些语言中略有不同。Common Lisp关键字和Clojure关键字之间的一些区别:
Clojure中的关键字不是符号。
user> (symbol? :foo)
false
关键字不属于任何命名空间,除非你明确地对它们进行限定:
user> (namespace :foo)
nil
user> (namespace ::foo)
"user"
(感谢Rainer Joswig提供了我需要查看的内容。)
(eval (eval ':a))
vs (eval (eval ''a))
。还有其他优点吗?在性能方面,它们是相同的吗? - kristianlmCommon Lisp有关键字符号。
关键字也是符号。
(symbolp ':foo) -> T
:foo
被Common Lisp读取器解析为符号keyword::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
包。
许多集合都会特别处理关键字,这使得一些非常方便的语法得以实现。
(:user-id (get-users-map))
是与
相同的意思。((get-users-map) :user-id)
对于关键词,当关键词首次构建时,会计算并缓存哈希值。在将关键词作为哈希键查找时,它只会返回预先计算的哈希值。对于字符串和符号,每次查找都会重新计算哈希。
同名的关键词之所以始终相同,是因为它们包含自己的哈希值。由于在映射和集合中搜索是从哈希键进行的,因此在大量搜索的情况下可以提高搜索效率,而不是搜索本身。
关键字是全局的,符号则不是。
这个例子是用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)