def的clojure行为

时间:2012-06-19 15:11:20

标签: clojure leiningen

我有一个lein项目(使用cascalog - 但这并不是特别重要)。我正在尝试外部化属性,如文件路径,所以我最终得到的代码如下所示:

(defn output-tap [path] (hfs-textline (str (get-prop :output-path-prefix) path) :sinkmode :replace))

(def some-cascalog-query 
    (<- [?f1 ?f2 ?f3] 
        ((output-tap (get-prop :output-path)) ?line)
        (tab-split ?line :> ?f1 ?f2 ?f3)))

在上面的例子中,假设函数get-prop存在;它只是使用标准的java来读取属性值(基于这个例子:loading configuration file in clojure as data structure)。

现在我有一个加载属性值的main方法,例如类似的东西:

(defn -main [& args] (do (load-props (first args)) (do-cascalog-stuff)))

但是当我lein uberjar时出现编译时错误:

Caused by: java.lang.IllegalArgumentException: Can not create a Path from an empty string
at org.apache.hadoop.fs.Path.checkPathArg(Path.java:82)
at org.apache.hadoop.fs.Path.<init>(Path.java:90)
at cascading.tap.hadoop.Hfs.getPath(Hfs.java:343)

defs是否始终评估编译时间(而不是运行时评估)?或者我误解了这个错误?

2 个答案:

答案 0 :(得分:3)

那么,您希望在运行时进行属性查找吗?然后是的,您需要将some-cascalog-query定义为函数或宏。裸def导致在加载代码时计算表达式,而不是在取消引用var时。

这可以在REPL中简单说明:

user=> (def foo (do (println "Hello, world!") 1))
Hello, world!
#'user/foo
user=> foo
1

来自documentation(强调我的):

  

(def符号init?)

     

使用符号名称和当前命名空间值( ns )的命名空间创建并实习或定位全局var。 如果提供了init,则会对其进行求值,并将var的根绑定设置为结果值。

答案 1 :(得分:0)

该错误看起来像(get-prop :output-path) (get-prop :output-path-prefix)正在返回由str包裹到空字符串中的任何内容。也许房产没有找到?

get-prop是否按预期工作?

你对defs的理解是正确的,它们是编译时间,而不是(通常)运行时。