在将元素索引传递给“key”参数的向量和中,reduce-kv按预期工作。但是,在子向量和中会失败,因为clojure.lang.APersistentVector$SubVector没有实现IKVReduce。
(reduce-kv + 0 (link: 1 2 3))
9
(reduce-kv + 0 (subvec (link: 1 2 3) 1))
IllegalArgumentException No implementation of method: :kv-reduce of protocol: #'clojure.core.protocols/IKVReduce found for class: clojure.lang.APersistentVector$SubVector clojure.core/-cache-protocol-fn (core_deftype.clj:583)
一个解决方案是将子向量和复制到向量中
(reduce-kv + 0 (into (link: ) (subvec (link: 1 2 3) 1)))
6
然而,这里的vec不会起作用。从Clojure 1.7开始,vec会返回一个子向量和而不是复制。
(reduce-kv + 0 (vec (subvec (link: 1 2 3) 1)))
IllegalArgumentException No implementation of method: :kv-reduce of protocol: #'clojure.core.protocols/IKVReduce found for class: clojure.lang.APersistentVector$SubVector clojure.core/-cache-protocol-fn (core_deftype.clj:583)
Clojure用户期望子向量和支持所有常规向量操作,而此异常令人困惑。问题的原因是子向量和返回一个 clojure.lang.APersistentVector$SubVector,它没有实现 clojure.lang.IKVReduce。PersistentVector继承自APersistentVector并实现IKVReduce,但SubVector没有获得任何IKVReduce支持。这可能是疏忽造成的。
附有两个补丁。第一个补丁通过扩展core.clj中的IKVReduce协议解决了问题。这为Clojure用户提供了一个方便的方案,可以通过将补丁直接添加到代码中作为解决方案。第二个补丁添加了直接到APersistentVector$SubVector的Java实现IKVReduce接口。应审查第二个补丁。两个补丁都包含相同的测试。