【问题标题】:Make a Java class work as a sequence in Clojure使 Java 类在 Clojure 中作为序列工作
【发布时间】:2012-10-19 01:15:19
【问题描述】:

我正在使用一个表示结果序列的 Java 类(有点像 Clojure 向量)。

我想将这个类与典型的 Clojure 序列函数一起使用(即我想让这个类表现得好像它支持序列抽象)但是我不能更改类所以我无法使其实现clojure.lang.Seqable 或类似的。此外,令人讨厌的是,该类没有实现 java.util.Collectionjava.lang.Iterable

我可以看到几个选项:

  • 在对象的(现有)迭代器上使用iterator-seq
  • 将对象包装在另一个实现java.util.Collection/clojure.lang.Sequable的类中
  • 创建一个函数,通过查询对象来构建 Clojure 向量或序列

还有其他选择吗?最好的方法是什么?

【问题讨论】:

  • iterator-seq 似乎很好,在内部它与您关于包装对象的第二点相同

标签: java clojure sequence clojure-java-interop


【解决方案1】:

最快最直接的方法是使用iterator-seq

这确实引出了一个问题:为什么核心 Clojure 不提供像 SeqSource 这样由seq 调用的协议。然后可以“扩展”非标准集合以提供序列,类似于 InternalReduce 对reduce 的工作方式。

【讨论】:

  • 因为 seq (a) 被编译器使用,因此需要对 java 友好(即接口),并且 (b) 非常非常频繁地调用它,因此它需要尽可能快 - 协议比很多东西都快,但不如简单的接口调度快。
  • @amalloy 然后可能是 to-seq 函数
  • “另外,令人讨厌的是,该类没有实现 java.util.Collection 或 java.lang.Iterable。”
  • @noahz 但是,从原始问题来看,“对象的(现有)迭代器”意味着有一个可用的迭代器。鉴于创建代理似乎有点矫枉过正。如果没有迭代器,那么当然可以使用其他方法
  • 添加一个名为to-seq 的函数与seq 做同样的事情根本不能解决任何问题。它仍然需要编译器可以访问,当然没有 clojure 函数。
【解决方案2】:

Use proxy 扩展类并使其实现ISeq

【讨论】:

    【解决方案3】:

    我的第一个尝试是创建该对象的惰性序列:

    (defn sequify [obj]
      (letfn [(inner [idx] 
                     (when (< idx (.size obj))
                              (cons (.get obj idx)
                                    (lazy-seq 
                                      (inner (inc idx))))))]
        (inner 0)))
    

    只需将.size.get 替换为适当的方法即可。

    lazy-seq 解决方案相比,如果您想提高性能,编写包装器可能更合适。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-06
      • 1970-01-01
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多