Clojure: Lein运行无法解析符号

14

我刚开始使用lein进行我的第一个Clojure项目,这里是代码:

(ns fileops.core
  (:use
    [clojure.core :only (slurp)]
    [clojure-csv.core :only (parse-csv)]
    [fileops.core]))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (read-file "sample.csv"))

(defn read-file
  "open and read the csv file"
  [fname]
  (with-open [file (clojure.java.io/reader fname)]
    (parse-csv (slurp fname))))

我尝试使用 "lein run" 运行此程序,但一直出现以下错误:
Caused by: java.lang.RuntimeException: Unable to resolve symbol: read-file in this context
    at clojure.lang.Util.runtimeException(Util.java:219)
    at clojure.lang.Compiler.resolveIn(Compiler.java:6874)
    at clojure.lang.Compiler.resolve(Compiler.java:6818)
    at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6779)
    at clojure.lang.Compiler.analyze(Compiler.java:6343)
    ... 52 more

我做错了什么?


6
你的源代码中应该先使用read-file再使用main。 - Diego Basch
@DiegoBasch,你真是救星啊。我刚接触Clojure,花了太多时间试图弄清楚为什么我的函数在错误的上下文中被调用。就是这个问题……一直都是这个问题。非常棒的帖子。 - Joshua Schlichting
2个回答

16
您仅使用了Clojure核心库中的slurp函数,这意味着您现在无法使用任何其他核心函数 :)尝试将您的ns更改为使用:require而不是:use,因为这更符合惯用法。
需要注意的一点是,在Clojure中,顺序很重要,因此如果您不像在C和某些其他语言中那样在文件顶部声明一个函数,则较早声明的函数将无法引用它们。这是以前导致错误的原因,也是我喜欢将我的-main函数定义在底部的原因之一。这是风格问题。
另一件事是,您的-main函数现在正在接受可变参数并且没有使用它们。在Clojure中,使用_来引用不使用的参数是惯用的。您可以使用& _避免错误消息,以防用户传递不必要的参数,但我会从一开始就让-main函数没有参数。因为运行程序时不需要提供任何内容,错误确实使调试更容易。了解正在使用和位置很重要。sample.csv文件已经提供并且已对其调用read-file,因此如果您的read-file函数正确并且sample.csv文件位于适当的位置,则应该运行该程序。
关于您的-main函数,最好在其中放入一个小测试,以查看在运行时是否正确执行,因此我将其更改为将csv文件的内容打印到控制台上。从文件中打印的方式很有效,值得学习。
最后,请确保在您的project.clj文件中包含clojure-csv.core。
core.clj:
(ns fileops.core
  (:require
    [clojure-csv.core :refer [parse-csv]]))

(defn read-file
  "open and read the csv file"
  [fname]
  (with-open [file (clojure.java.io/reader fname)]
    (parse-csv (slurp fname)))) 

 (defn -main []
        (println (clojure.string/join "\n" (read-file "resources/test.csv"))))

project.clj:

...

:dependencies [[org.clojure/clojure "1.5.1"]
               [clojure-csv/clojure-csv "2.0.1"]
                ...]
:main fileops.core

你需要将fileops.core声明为:main,就像上面展示的那样。这告诉Leiningen在输入lein run时执行哪个函数。这是非常重要且棘手的事情。

现在确保你在项目目录的根目录下,在终端中运行以下命令:

lein clean
lein deps 
lein run 

祝你好运!

更多阅读:

8th light关于命名空间的博客

flying machine studios解释lein run的方法


1

在你的源代码中,read-file 应该在 main 之前,或者你应该在 -main 之前加上一个声明语句,例如:

(declare read-file)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接