我写了这个函数,但它的返回值是什么。
(defn read-data [file]
(let [code (subs (.getName file) 0 3)]
(with-open [rdr (clojure.java.io/reader file)]
(drop 1 (line-seq rdr)))))
(def d (read-data "data.db"))
现在好了。但是,当我想打印出来时。
(clojure.pprint/pprint d)
我有一个例外:
Exception in thread "main" java.lang.RuntimeException: java.io.IOException: Stream closed
所以我很困惑,怎么了?返回值不是列表?如何在这种情况下作为新手调试?
谢谢!
答案 0 :(得分:3)
问题是line-seq
是懒惰的,读者在评估时会被关闭。
这意味着需要在with-open
范围内阅读所有行。一种选择是使用line-seq
强制对doall
进行全面评估,如下所示。
(drop 1 (doall (line-seq rdr)))
这种方法的一个潜在问题是,如果文件大于可用内存,则会出现OutOfMemoryError。因此,根据您要完成的任务,可能会有其他内存不足的解决方案。
答案 1 :(得分:2)
例如,您可以使用闭包并修改“line-seq”用于自动关闭阅读器:
(defn line-seq2 [^java.io.BufferedReader rdr]
(if-let [line (.readLine rdr)]
(cons line (lazy-seq (line-seq2 rdr)))
(.close rdr)))
(defn my-reader [file]
(let [lines (line-seq (clojure.java.io/reader file))]
(fn [] lines)))
(def d (my-reader "data.db"))
现在变量“d”是一个函数:
user> (drop 1 (d))
=> ... file body except first line ...
答案 2 :(得分:1)
(drop 1 (line-seq rdr))
该行返回一个序列,即惰性或流。所以基本上文件阅读器rdr在执行此行时实际上并未读取,但是当您尝试在print方法中访问此序列时,line-seq
函数正在读取rdr,但正如您正在使用{{ 1}},当执行流出with-open
时,该rdr已经关闭。
请参阅with-open
以便在创建时对延迟序列进行评估。我建议你阅读FP中的懒惰和特别是Clojure的序列,以便更好地理解懒惰的评估。