Clojure макрос для чтения файла - PullRequest
2 голосов
/ 06 января 2012

Я хочу создать макрос Clojure, который может читать файл, когда файл успешно прочитан, поток должен быть закрыт.

(import '(java.io FileReader File))

(defmacro read([x y]
`(let ~x 
  (try ~y 
   (. x close)
    (catch Exception e# e#))))) 

Вызывается так:

(read [stream (java.io.FileReader (java.io.File "somefile.txt"))] (. stream read)))

Приводит к этой ошибке

java.lang.Exception: No such var: user/x (NO_SOURCE_FILE:8) 

У кого-нибудь есть предложения, спасибо.

Ответы [ 2 ]

11 голосов
/ 06 января 2012

Разве вы не ищете with-open, если только по какой-то причине вы не хотите явно использовать макрос?

(defn read [file-name]
  (with-open [reader (BufferedReader. (FileReader. file-name))]
    (doseq [line (line-seq reader)] (println line))))

Согласно странице ClojureDocs , это гарантирует, что читатель будет закрыт в конце формы.

Надеюсь, это поможет!

1 голос
/ 06 января 2012

Да, и если я цитирую "~ x", это исключение выдается

<IllegalArgumentException java.lang.IllegalArgumentException: No matching field found: close for class clojure.lang.PersistentVector>

Это потому, что '~x" теперь относится к [stream (FileReader. (File. "somefile.txt"))]. Ошибка, которую вы получаете, имеет смысл. Макрос выплевывает код, который пытается вызвать close() в указанном выше векторе. Вы можете поэкспериментировать с использованием (first ~x).

Обратите внимание, что этот макрос является чрезвычайно общим и существенно не уменьшает объем кода, который должен писать пользователь.

Вы можете попробовать что-то в этом направлении (это, вероятно, не работает)

(import '(java.io FileReader File))

(defmacro read([fname]
`(try
   (let [stream# (FileReader. (File. ~fname))
         rtnval (. stream# read)]
     (do 
       (. stream# close)
       rtnval))
   (catch Exception e# e#)))

Но я только на 50% уверен, что мой ответ имеет какой-либо смысл.

...