reduce-kv在与元素索引作为"键"参数传递的向量上按预期工作。然而,使用subvec时它失败了,因为clojure.lang.APersistentVector$SubVector没有实现IKVReduce。
(reduce-kv + 0 (link: 1 2 3))
9
(reduce-kv + 0 (subvec (link: 1 2 3) 1))
IllegalArgumentException找不到类:clojure.lang.APersistentVector$SubVector的协议:#'clojure.core.protocols/IKVReduce的方法::kv-reduce clojure.core/-cache-protocol-fn (core_deftype.clj:583)
一种解决方法是将subvec复制到一个向量中
(reduce-kv + 0 (into (link: ) (subvec (link: 1 2 3) 1)))
6
然而,vec在这里不可用。从Clojure 1.7开始,vec将返回一个subvec而不是复制。
(reduce-kv + 0 (vec (subvec (link: 1 2 3) 1)))
IllegalArgumentException找不到类:clojure.lang.APersistentVector$SubVector的协议:#'clojure.core.protocols/IKVReduce的方法::kv-reduce clojure.core/-cache-protocol-fn (core_deftype.clj:583)
Clojure用户期望子向量支持所有正常的向量操作,这个异常很令人困惑。问题产生的原因是subvec返回一个clojure.lang.APersistentVector$SubVector,它没有实现clojure.lang.IKVReduce。PersistentVector从APersistentVector继承并实现IKVReduce,但SubVector没有IKVReduce支持。这可能是疏忽造成的。
附上了两个补丁。第一个补丁通过在core.clj中扩展IKVReduce协议来解决问题。这对于Clojure用户来说作为一个解决方法是方便的。第二个补丁建议由Alex Miller直接在APersistentVector$SubVector中添加IKVReduce接口的Java实现。第二个补丁应该是被审查的补丁。这两个补丁中包含相同的测试。