Каково возвращаемое значение этой функции? - PullRequest
3 голосов
/ 03 апреля 2012

Я пишу эту функцию, но каково ее возвращаемое значение.

(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 ]

3 голосов
/ 03 апреля 2012

Проблема в том, что line-seq ленив и что читатель закрыт к моменту оценки.

Это означает, что все строки должны быть прочитаны в пределах вашей with-open. Один из вариантов - принудительно выполнить полную оценку line-seq, используя doall, как показано ниже.

(drop 1 (doall (line-seq rdr)))

Потенциальная проблема этого подхода заключается в том, что вы получите ошибку OutOfMemoryError, если файл больше доступной памяти. Поэтому, в зависимости от того, что вы пытаетесь достичь, могут быть и другие решения, не требующие большого объема памяти.

2 голосов
/ 03 апреля 2012

В качестве примера вы можете использовать замыкание и измененный «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 ...
1 голос
/ 03 апреля 2012
(drop 1 (line-seq rdr))

Эта строка возвращает последовательность, то есть лентяй или поток. Таким образом, в основном программа чтения файлов rdr фактически не читается, когда эта строка выполняется, но когда вы пытаетесь получить доступ к этой последовательности в вашем методе печати, тогда rdr читается функцией line-seq, а поскольку вы используете with-open, этот rdr уже закрыт, когда поток выполнения выходит из with-open.

Пожалуйста, обратитесь к doall, чтобы выполнить ленивую последовательность при ее создании. Я бы посоветовал вам прочитать о лени в FP в целом и о последовательностях в частности, чтобы Clojure лучше понимал ленивые вычисления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...