这个问题让我深入研究了 Clojure 源代码。为了弄清楚这一点,我只花了几个小时将打印语句放入源代码中。
事实证明,这两个映射表达式是通过不同的代码路径评估的
(type {:a 1})
导致发出并运行 Java 字节码。发出的代码用于clojure.lang.RT.map()
构造为小地图返回PersistentArrayMap的地图:
static public IPersistentMap map(Object... init){
if(init == null)
return PersistentArrayMap.EMPTY;
else if(init.length <= PersistentArrayMap.HASHTABLE_THRESHOLD)
return PersistentArrayMap.createWithCheck(init);
return PersistentHashMap.createWithCheck(init);
}
(def x {:a 1})
至少从 REPL进行评估时,不会发出字节码。常量映射被解析为PersistentHashMap,clojure.lang.Compiler$MapExpr.parse()
其中返回它在 a 中扭曲它ConstantExpr
:
else if(constant)
{
IPersistentMap m = PersistentHashMap.EMPTY;
for(int i=0;i<keyvals.length();i+= 2)
{
m = m.assoc(((LiteralExpr)keyvals.nth(i)).val(), ((LiteralExpr)keyvals.nth(i+1)).val());
}
//System.err.println("Constant: " + m);
return new ConstantExpr(m);
}
def
评估时的表达式绑定ConstantExpr
上面创建的值,如前所述,它是PersistentHashMap。
那么为什么要这样实现呢?
我不知道。这可能是简单的疏忽,或者 PersistentArrayMap 优化可能并不值得。