5

我正在使用一个 java 类在 clojure 中工作,该类为包含一系列记录的域特定二进制文件提供检索 API。

java 类用一个文件初始化,然后提供一个.query方法,该方法返回一个只有一个方法的内部类的实例.next,因此不能很好地使用通常的 java 集合 API。外部类和内部类都没有实现任何接口。

.query方法可能返回 null 而不是内部类。该.next方法返回一个记录字符串,如果没有找到更多记录,则返回 null,它可能会在第一次调用时立即返回 null。

如何在不编写更多 Java 类的情况下使这个 Java API 在 clojure 中正常工作?

我能想到的最好的是:


(defn get-records
  [file query-params]
  (let [tr (JavaCustomFileReader. file)]
    (if-let [inner-iter (.query tr query-params)] ; .query may return null                                                               
      (loop [it inner-iter
             results []]
       (if-let [record (.next it)]
         (recur it (conj results record))
         results))
      [])))

这给了我一个与 clojure seq 抽象一起使用的结果向量。是否有其他方法可以从 java API 公开序列,无论是使用惰性序列还是使用协议?

4

3 回答 3

4

您的代码并不像使用 Iterable 时那样惰性,但您可以使用惰性序列填补空白,如下所示。

(defn query-seq [q]
  (lazy-seq
    (when-let [val (.next q)]
      (cons val (query-seq q)))))

也许您应该包装查询方法以保护自己免受第一个空值的影响。

于 2012-07-10T17:44:40.707 回答
4

似乎很适合lazy-seq

(defn query [file query]
  (.query (JavaCustomFileReader. file) query))

(defn record-seq [query]
  (when query
    (when-let [v (.next query)]
      (cons v (lazy-seq (record-seq query))))))

;; usage:
(record-seq (query "filename" "query params"))
于 2012-07-10T17:59:04.500 回答
4

不下降到lazy-seq

(defn record-seq
  [q]
  (take-while (complement nil?) (repeatedly #(.next q))))

而不是(complement nil?)你也可以只使用identityif.next不返回 boolean false

(defn record-seq
  [q]
  (take-while identity (repeatedly #(.next q))))

我还会对入口点进行一些重组。

(defn query
  [rdr params]
  (when-let [q (.query rdr params)]
    (record-seq q)))

(defn query-file
  [file params]
  (with-open [rdr (JavaCustomFileReader. file)]
    (doall (query rdr params))))
于 2012-07-11T06:17:12.550 回答