如何获得一个调用Java方法的Fn?

时间:2012-11-05 09:39:24

标签: clojure

我正在学习Clojure。我编写了这段代码来递归遍历一个目录。

(tree-seq #(.isDirectory %1) #(.listFiles %1) (File. "/my-directory"))

为什么我不能将.isDirectory用作Clojure中的第一类函数?有没有更好的方法来重写这段代码?

4 个答案:

答案 0 :(得分:7)

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互操作
  • 中抽象出来

答案 1 :(得分:6)

Java方法不是clojure函数,因为你不能自己调用​​方法;你必须在一个对象上调用一个方法,它必须是该方法所期望的类型的对象。换句话说,在java中,方法不能与其定义类完全分离(至少不能有效)。

#(。foo%)的另一种选择是(memfn foo),在#(...)被引入之后几乎没有人再使用它了。

答案 2 :(得分:1)

您可以查看sourcecode of file-seq(使用树序列)查看其工作原理。

顺便说一下:你的代码对我来说非常好。我只需要在REPL中使用java.io.File而不是File,因此它知道Java类。

答案 3 :(得分:1)

您已经获得了正确的答案,但只是添加了更多Clojure惯用代码,我还会使用

#(.foo %)
正如Joost Diepenmaat所做的那样(但我相信它可能会被忽视)。

我还建议阅读Listing files in a directory in Clojure