Clojure中def内的'@foo类为何是Cons而非PersistentList?
原因说明
前置规则
- Clojure 读取器会优先处理前缀读取器宏:
'是quote宏的简写,@是deref宏的简写,因此'@foo会被等价展开为'(deref foo),即被quote包裹的两元素列表(deref foo)。 - Clojure 编译器默认开启常量内存优化,对编译期可确定的常量值,会优先用开销更低的结构存储。
两类场景的差异
- 直接执行
(class '@foo)时,'@foo展开的两元素列表是函数调用的临时参数,不属于需要长期存储的编译期常量,因此会用通用的clojure.lang.PersistentList结构存储,返回结果符合预期。 - 执行
(def x '@foo)时,'@foo展开的两元素列表是def绑定的全局常量值,会触发编译器优化:长度为2的短列表会被转换为更轻量的clojure.lang.Cons结构存储(Cons仅存储当前元素和尾部指针,内存开销远低于PersistentList),因此查询x的类型会得到Cons。
补充说明
该行为并非 '@foo 特有,所有长度为2的被quote字面量列表作为def的绑定值时都会触发该优化,你可以执行下面的代码验证:
(def y '(a b)) (class y) ;; 同样返回 clojure.lang.Cons
你之前测试其他形式没有触发,大概率是因为其他quote形式展开后的长度大于2,不属于优化覆盖范围。
内容的提问来源于stack exchange,提问作者Rafał Dowgird
相关产品推荐
相关产品推荐

