读取文本文件时的Clojure异常

时间:2013-12-28 19:25:23

标签: clojure sequence

我只是想读一个标准的linux' / etc / passwd' file:拆分成记录。 这似乎工作(所有行都回显到终端)但最后抛出一个异常? (见下文)

该计划的内容是什么?

(use 'clojure.java.io)
(use 'clojure.string)

(defn process_file[infile] (
        (defstruct user :username
                        :password
                        :uid
                        :gid
                        :comment
                        :home_dir
                        :shell)

        (def record_separator #":")

        (with-open [rdr (reader infile)]
                (doseq [line (line-seq rdr)]
                        (def fields (split line record_separator) )
                        (def user_record (apply struct user fields) )
                        (println (user_record :username) )
                )
        )
        )
)

; main
(process_file "/etc/passwd")


[ after all the lines read have been output ]
    Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentStructMap$Def cannot be cast to clojure.lang.IFn
        at clojure.lang.Var.fn(Var.java:392)
        at clojure.lang.Var.invoke(Var.java:419)
        at user$process_file.invoke(readfile.clj:15)
        at user$eval14.invoke(readfile.clj:26)
        at clojure.lang.Compiler.eval(Compiler.java:6514)
        at clojure.lang.Compiler.load(Compiler.java:6955)
        at clojure.lang.Compiler.loadFile(Compiler.java:6915)
        at clojure.main$load_script.invoke(main.clj:283)
        at clojure.main$script_opt.invoke(main.clj:343)
        at clojure.main$main.doInvoke(main.clj:427)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at clojure.lang.Var.invoke(Var.java:415)
        at clojure.lang.AFn.applyToHelper(AFn.java:161)
        at clojure.lang.Var.applyTo(Var.java:532)
        at clojure.main.main(main.java:37)


java version "1.7.0_21"
OpenJDK Runtime Environment (IcedTea 2.3.9) (7u21-2.3.9-1ubuntu1)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)


Clojure 1.4.0

2 个答案:

答案 0 :(得分:7)

你的整个函数体周围有一组额外的括号。删除它看起来如下(虽然我不建议这样编写代码,见下文):

(defn process_file[infile]
  (defstruct user :username
             :password
             :uid
             :gid
             :comment
             :home_dir
             :shell)

  (def record_separator #":")

  (with-open [rdr (reader infile)]
    (doseq [line (line-seq rdr)]
      (def fields (split line record_separator))
      (def user_record (apply struct user fields))
      (println (user_record :username)))))

在你的程序中,你在一个函数中使用def,这是不鼓励的。编写代码的一种更惯用的方法是使用命名空间,并在函数外部定义结构和记录分隔符,然后在函数中使用let作为局部变量。以这种方式重新格式化代码如下所示:

(ns scratch
  (:require
   [clojure.java.io :as io]
   [clojure.string :as string]))

(defstruct user-rec
  :username
  :password
  :uid
  :gid
  :comment
  :home-dir
  :shell)

(def record-separator #":")

(defn process-file [fname]
  (with-open [rdr (io/reader fname)]
    (doseq [line (line-seq rdr)]
      (let [fields (string/split line record-separator)
            user   (apply struct user-rec fields)]
        (println (format "user: %s" user))))))


(process-file "/etc/passwd")

上面的代码运行,打印出为密码文件的每一行创建的结构。

答案 1 :(得分:4)

您的例外原因是defstruct来电之前的额外括号。函数在表单中处于领先位置,因此编译器会尝试将defstruct的结果强制转换为函数,因此异常。