Clojure 的符号文字 are documented 需要以非数字字符开头。这与 Java 标识符或数字文字语法无关——Clojure 符号文字是 clojure.lang.LispReader 的 read 方法作为符号读入的任何内容,并且在 Clojure 符号文字中允许使用许多字符,这些字符在Java 标识符(例如-、>...;还有一种将它们转换为字符序列的方案,例如_GT_ 用于> 用于互操作目的)。错误的直接原因是clojure.lang.LispReader/read 在看到一个数字后立即分派给readNumber,并且没有办法“退出”。
为了完整起见,进行切线讨论。
注意,如果你手工构造一个符号,你可以用它来命名一个Var:
;; Clojure's intern serves a different purpose to CL's intern, see (doc intern)
user> (intern *ns* (symbol "1+") inc)
#'user/1+
user> ((ns-resolve *ns* (symbol "1+")) 1)
2
你甚至可以做一些时髦的事情,比如
user> (eval `(defrecord ~(symbol "1foo") []))
user.1foo
user> user.1foo
user.1foo
user> (user.1foo.)
#:user.1foo{}
...这当然是完全疯狂的,虽然可能没有那么多
user> (in-ns (symbol "1foo"))
#<Namespace 1foo>
1foo> (clojure.core/refer-clojure)
nil
1foo> (defrecord Foo [])
1foo.Foo
1foo> (in-ns 'user)
#<Namespace user>
user> (1foo.Foo.)
; Evaluation aborted. ;; can't do that
user> (eval `(new ~(symbol "1foo.Foo")))
#:1foo.Foo{}
我想如果坚持做这种事情,最终会遇到 JVM 的限制。这样做当然没有什么好的目的......无论如何,回到最初的问题,1+ 引起的错误与符号文字语法有关,它对 Java 友好仅在合理的“翻译”的范围内“存在。具有名称的 Clojure 对象不太关心这些名称的格式是否正确,尽管使用时髦的名称很不方便并且绝对不支持。
(上面示例中的user.1foo 实际上是一个Java 类——我有点惊讶地看到这个类确实有效,但另一方面,我似乎记得JVM 对名称的内部限制是应该不如 Java 严格。)