为什么绑定会影响我的地图类型?

时间:2012-08-16 16:33:18

标签: map clojure language-implementation

我在REPL中玩耍时有一些奇怪的行为:

Clojure 1.4.0
user=> (type {:a 1})
clojure.lang.PersistentArrayMap
user=> (def x {:a 1})
#'user/x
user=> (type x)
clojure.lang.PersistentHashMap

我认为所有小的文字地图都是PersistentArrayMap的实例,但显然如果它与def绑定的情况并非如此。为什么使用def会导致Clojure为我的litte地图选择不同的表示?我知道这可能只是一些奇怪的实现细节,但我很好奇。

1 个答案:

答案 0 :(得分:15)

这个问题让我深入研究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);
}

至少从REPL评估(def x {:a 1})时,没有发出字节码。常量映射在clojure.lang.Compiler$MapExpr.parse()中被解析为 PersistentHashMap ,它将其返回到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优化可能不值得。