我正在学习 Clojure。我编写了这段代码来递归地遍历一个目录。
(tree-seq #(.isDirectory %1) #(.listFiles %1) (File. "/my-directory"))
为什么我不能.isDirectory
在 Clojure 中用作一等函数?有没有更好的方法来重写这段代码?
我正在学习 Clojure。我编写了这段代码来递归地遍历一个目录。
(tree-seq #(.isDirectory %1) #(.listFiles %1) (File. "/my-directory"))
为什么我不能.isDirectory
在 Clojure 中用作一等函数?有没有更好的方法来重写这段代码?
Joost 指出 Java 方法不是一流的函数。
作为处理这个问题的一种方法,我通常喜欢将 Java 函数包装在 Clojure 函数中(或者找到一个已经这样做的库),然后很容易以惯用的一流方式使用它们:
(defn directory? [^java.io.File file]
(.isDirectory file))
(defn list-files [^java.io.File file]
(.listFiles %1))
(tree-seq directory? list-files (File. "/my-directory"))
这是几行代码,但具有以下优点:
Java 方法不是 clojure 函数,因为您不能单独调用方法;您必须在对象上调用方法,并且它必须是该方法期望的类型的对象。换句话说,在java中,一个方法不能与其定义的类完全分离(至少不是有效的)。
#(.foo %) 的替代方案是 (memfn foo),在引入 #(...) 之后几乎没有人再使用它。
您可以查看file-seq 的源代码(它使用 tree-seq)来了解它是如何工作的。
顺便说一句:你的代码对我来说效果很好。我只需要在 REPL 中使用 java.io.File 而不是 File,这样它就知道 Java 类。
你已经得到了正确的答案,但只是为了添加更多的 Clojure 惯用代码,我也会使用
#(.foo %)
正如 Joost Diepenmaat 所做的那样(但我相信它可能被忽视了)。
我还建议阅读Clojure 目录中的列表文件。