Clojure的 def 函数行为

3

我有一个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读取属性值(基于此示例:将配置文件作为数据结构在Clojure中加载)。
现在我有一个主方法来加载属性值,例如:
(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)

def 是否总是在编译时评估(而不是运行时评估)?还是我误解了这个错误?
2个回答

3

所以,您希望在运行时进行属性查找?那么是的,您需要将some-cascalog-query定义为函数或宏。裸露的def导致表达式在代码加载时被评估,而不是在变量被解引用时。

这可以在REPL中很简单地说明:

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

文档中(强调是我的):

(def symbol init?)

创建并在当前命名空间 (ns) 的值下将具有名称 symbol 的全局变量添加到符号表中。如果提供了 init,则会评估该值,并将变量的根绑定设置为生成的值。


0

这个错误看起来像是 (get-prop :output-path)(get-prop :output-path-prefix) 返回了空值,然后被 str 包装成了一个空字符串。也许这个属性没有被找到?

get-prop 的工作是否符合预期?

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


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