这个函数的返回值是多少?

时间:2012-04-03 03:40:45

标签: clojure

我写了这个函数,但它的返回值是什么。

(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

所以我很困惑,怎么了?返回值不是列表?如何在这种情况下作为新手调试?

谢谢!

3 个答案:

答案 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的序列,以便更好地理解懒惰的评估。