1

假设我想在 clojure 中打印 hbase 表扫描的输出。

(defmulti scan (fn [table & args] (map class args)))

(defmethod scan [java.lang.String java.lang.String] [table start-key end-key]
    (let [scan (Scan. (Bytes/toBytes start-key) (Bytes/toBytes end-key))]
        (let [scanner (.getScanner table scan)]
            (doseq [result scanner]
                (prn
                    (Bytes/toString (.getRow result))
                    (get-to-map result))))))

get-to-map 将结果转换为地图。它可以像这样运行:

(hbase.table/scan table "key000001" "key999999")

但是如果我想让用户对扫描结果做些什么呢?我可以允许他们将一个函数作为回调传递给每个结果。但我的问题是:如果我希望用户能够懒惰地迭代每个结果,我应该返回什么

(Bytes/toString (.getRow result))
(get-to-map result)

并且不保留以前的结果,这可能发生在使用惰性序列的简单化实现中。

4

1 回答 1

1

如果你接受一个回调参数,你可以在里面调用它doseq

(defmulti scan [f table & args] (mapv class args)) ; mapv returns vector

(defmethod scan [String String] [f table start-key end-key]
               ; ^- java.lang classes are imported implicitly
  (let [scan ...
        scanner ...] ; no need for two separate lets
    (doseq [result scanner]
      ; call f here, e.g.
      (f result))))

f每个结果都会调用这里一次。它的返回值以及结果本身将立即被丢弃。您当然可以调用f一些预处理版本result,例如(f (foo result) (bar result)).

您还可以将结果的序列/向量返回给客户端并让它自己处理。如果序列是惰性的,您需要确保支持它的任何资源在处理期间保持打开状态(并且可能稍后关闭它们 - 请参阅with-open;处理代码需要在内部执行with-open并使用返回时处理)。

例如,要将预处理结果的向量返回给客户端,您可以这样做

(defmethod scan ...
  (let [...]
    (mapv (fn preprocess-result [result]
            (result->map result))
          scanner)))

然后,客户可以对他们做任何想做的事情。用于map返回惰性序列。如果客户端随后需要打开/关闭资源,您可以接受它作为扫描的参数,以便客户端可以说

(with-open [r (some-resource)]
  ; or mapv, dorun+map, doall+for, ...
  (doseq [result (scan r ...)]
    (do-stuff-with result)))
于 2013-05-02T00:56:38.380 回答