在Clojure命名空间中排除java.lang.*

8

有没有可能在Clojure命名空间中排除java.lang类名?

我需要使用Byte和String这样的变量,但是java.lang类名阻碍了我的进展。

也许可以使用(ns my-ns (:exclude java.lang))之类的方式来实现?


1
clojure.core 命名空间依赖于 java.lang.* 中的许多内容,因此即使您可以重新定义这些类,我也不确定这是否是一个好主意。例如,strkeywordfor 是使用 java.lang.String 类的函数和宏。 - Brian Cooley
1
我认为只要这些不是宏并且在运行时使用“String”,那么这应该不会成为问题。我还可以排除其他函数使用的clojure.core函数,因为它们在内部完全限定。因此,在内部使用java.lang.String时使用String不应该成为问题。 - Dominik G
出于好奇,你为什么需要将变量命名为 ByteString - Gert
1
我正在用Clojure实现Shen,在Shen Byte和String的核心代码中使用了它。 - Dominik G
根据shen网站的说法,它已经在Clojure上运行了?也许看看它是如何做到的会回答你的问题? - Tim X
3个回答

9
如果您使用全限定名称,就不会有歧义。例如:
user=> (def user/Byte (java.lang.Byte/decode "0"))
#'user/Byte

如果您以这种方式定义了Byte,那么Byte将解析为您的定义而无需限定名称。

user=> Byte
0

3

如果您在创建自己的映射之前手动删除了对java.lang.String的内置映射,则这是完全可能的:

$ cake repl
repl-1=> (def String 1)
java.lang.Exception: Expecting var, but String is mapped to class java.lang.String (NO_SOURCE_FILE:1)
repl-1=> (ns-unmap *ns* 'String)
nil
repl-1=> (def String 1)
#'repl-1/String
repl-1=> String
1

我也想强调其他评论的一些观点,定义一个名为String的东西不太可能让你的生活变得愉快/方便。


1

我对你的问题没有明确的答案,但我的猜测是,如果不修改Clojure本身,你是做不到的。以下是我的分析:

String符号作为默认映射的一部分在clojure/lang/Namespace.java中被interned(请参见该类中的Namespace构造函数,该函数引用clojure/lang/RT.java类中的DEFAULT_MAPPINGS)。Interning意味着,在Namespace类的成员变量中有一个键。这意味着每个命名空间都从String映射到String.class(请参见clojure 1.4.0中RT.java的第77行)。

ns宏中,您可以执行以下操作:

(ns my-ns
    (:refer-clojure :exclude [<mapping to exclude>]))

但是这只是跳过了内部新符号的代码(请参见clojure 1.4.0中clojure/core.clj的第3770行),因此它无法帮助您从命名空间映射中删除String

最后,如果您尝试使用类似于(defn String ...)的东西重新定义String的映射,则编译器会抱怨,因为String.class不是Var的实例。有关详细信息,请参见clojure 1.4.0中clojure/lang/Compiler.java的第6797行)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接