【问题标题】:How to get an Fn which calls a Java method?如何获得调用 Java 方法的 Fn?
【发布时间】:2012-11-05 09:39:23
【问题描述】:

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

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

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

【问题讨论】:

    标签: clojure


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      Java 方法不是 clojure 函数,因为您不能单独调用方法;您必须在对象上调用方法,并且它必须是该方法期望的类型的对象。换句话说,在 java 中,一个方法不能与其定义的类完全分离(至少效率不高)。

      #(.foo %) 的替代方案是 (memfn foo),在引入 #(...) 之后几乎没有人再使用它了。

      【讨论】:

        【解决方案3】:

        您可以查看sourcecode of file-seq(它使用树序列)来了解它是如何工作的。

        顺便说一句:您的代码对我来说非常有效。我只需要在 REPL 中使用 java.io.File 而不是 File,这样它就知道 Java 类。

        【讨论】:

          【解决方案4】:

          你已经得到了正确的答案,但只是为了添加更多的 Clojure 惯用代码,我也会使用

          #(.foo %)
          

          正如 Joost Diepenmaat 所做的那样(但我相信它可能被忽视了)。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-03
            • 2011-04-04
            • 2019-10-26
            • 1970-01-01
            相关资源
            最近更新 更多