为什么line-seq返回clojure.lang.Cons而不是clojure.lang.LazySeq ?



根据ClojureDocs的line-seq (http://clojuredocs.org/clojure_core/clojure.core/line-seq)和Stack问题的可接受答案(在Clojure 1.3中,如何读写文件),line-seq应该在传递java.io.BufferedReader时返回一个lazy seq。

但是,当我在REPL中进行测试时,该类型被列为clojure.lang.Cons。请看下面的代码:

=> (ns stack-question
     (:require [clojure.java.io :as io]))
nil
=> (type (line-seq (io/reader "test-file.txt")))
clojure.lang.Cons
=> (type (lazy-seq (line-seq (io/reader "test-file.txt"))))
clojure.lang.LazySeq

将line-seq调用封装在lazy-seq调用中会产生一个lazy seq,但根据文档,这应该是不必要的:line-seq无论如何都应该返回一个lazy seq。

注意:在REPL内部(我使用的是nrepl),似乎懒惰序列得到充分实现,所以我想也许这只是REPL的一个怪癖;然而,当我用Speclj测试它时,同样的问题也存在。另外,我不认为实现lazy seq与正在发生的事情有关。

编辑:所以我去检查源代码后,mobyte的回答说,在cons的尾部有一个lazy seq…

1   (defn line-seq
2     "Returns the lines of text from rdr as a lazy sequence of strings.
3     rdr must implement java.io.BufferedReader."
4     {:added "1.0"}
5     [^java.io.BufferedReader rdr]
6     (when-let [line (.readLine rdr)]
7       (cons line (lazy-seq (line-seq rdr)))))

对cons的调用可以解释为什么line-seq的返回值类型是clojure.lang.Cons。

您不需要"wrap"输出Cons,因为它已经有lazy seq作为"tail":

(type (line-seq (io/reader "test-file.txt")))
=> clojure.lang.Cons
(type (rest (line-seq (io/reader "test-file.txt"))))
=> clojure.lang.LazySeq
(type (cons 'a (rest (line-seq (io/reader "test-file.txt")))))
=> clojure.lang.Cons

编辑。

注意:在REPL内部(我使用的是nrepl),似乎延迟序列得到完全实现

不正确的。你可以测试它:

(with-open [r (io/reader "test-file.txt")] (line-seq r))
=> IOException Stream closed  java.io.BufferedReader.ensureOpen (BufferedReader.java:97)

这是因为line-seq返回未完全实现的lazy-seq,并且当repl稍后尝试实现结果以打印它时,reader已经关闭。但是如果你显式地实现它,它会给出正常的结果,没有任何异常:

(with-open [r (io/reader "/home/mobyte/2")] (doall (line-seq r)))
=> ...  output ...

相关内容

  • 没有找到相关文章

最新更新