请在 2024 Clojure 状态调查! 中分享您的想法。

欢迎!请参阅 关于页面 了解更多关于这项工作的信息。

+2
Clojure
已关闭

使用 java 方法引用 以下是有效操作(此代码来自 java.time.LocalDate)

public static LocalDate parse(CharSequence text, DateTimeFormatter formatter) {
    return formatter.parse(text, LocalDate::from);
}

解析方法的第二个参数是一个 TemporalQuery - 一个单一的 TemporalAccessor 作为参数的函数式接口。在这个例子中,不是传递 TemporalQuery 实例,而是传递了一个方法引用,其方法签名与 TemporalQuery 相匹配 - 即接受一个单一的 TemporalAccessor 作为参数。

尝试在 Clojure 中执行类似的操作

(^[CharSequence TemporalQuery] DateTimeFormatter/parse formatter "20200202" java.time.LocalDate/from)

结果如下

Execution error (ClassCastException) at user/eval2266 (form-init14137309762912529150.clj:1).

无法将类 user$eval2266$invokeLocalDate_from2268(在加载器 clojure.lang.DynamicClassLoader 的未知模块中)强制转换为类 java.time.temporal.TemporalQuery(user$eval2266$invokeLocalDate_from2268 在从加载器 'bootstrap' 的 java.base 模块中)

您认为这是一个错误还是故意的?如果是故意的,关于 Clojure 方法值与 Java 方法引用相比的文档会有所帮助。

已注明:“Clojure 1.12.0-alpha12 已发布”已关闭
截至 Clojure 1.12.0-alpha12,Clojure 函数将被隐式转换为必要的功能接口

(^[CharSequence TemporalQuery] DateTimeFormatter/.parse (DateTimeFormatter/ofPattern "yyyyMMdd") "20200202" java.time.LocalDate/from)

2 答案

+3

这将与下一个 alpha 版本中引入的新功能接口强制转换一起使用。

在基本层面上,Clojure 的 IFn 将自动转换为合适类型的接口(或者你可以在 let 绑定中请求显式的强制转换)。这是通过 invokedynamic 实现的,本质上与 Java lambda 编译所使用的机制相同(除了我们将使用一组固定的适配器目标,而不是动态生成合成 lambda 方法)。

新的方法值会实例化为 IFns,因此可以自动纳入其中,但正如你可以想象的那样,将 Java 方法包装到 Ifn 中,然后再将其适配回方法引用并不是最优的。幸运的是,我们可以在编译器中识别这种情况,并直接适配原始方法。

所以,它很快就要来了!这是 1.12 故事的一部分。

太棒了!感谢 Alex
0

Clojure 中的方法值本身是值。它是创建一个 lambda 函数的语法糖,该函数使用 Java 方法的正确重载。

Java 中的方法引用是创建用于特定上下文的正确事物的语法糖。你不能直接获取 LocalDate::from 的值 - 你必须将其放入 Java 编译器可以确定你确切要什么的环境中。

你的例子更多是关于 Java,而不是 Clojure。是 Java 编译器计算出所有签名,并发现它们是兼容的,使得可以使用 ...::from 的方式。

因为你只是调用了 parse 函数,所以使用 when 不是很合适

(^[CharSequence TemporalQuery] DateTimeFormatter/parse formatter x y)

相反,你可以使用

(.parse ^DateTimeFormatter formatter ^CharSequence x ^TemporalQuery y)

但是,这对你的情况没有帮助,因为 LocalDate/from 不是一个 TemporalQuery 的实例。在 Clojure 中,LocalDate/from 是一个常规的 Clojure 函数。即使你使用 ^[TemporalAccessor] LocalDate/from,它仍然是一个常规的 Clojure 函数,仅仅指向 那个 .../from 方法(在这里不重要,因为 LocalDate 中只有一个这样的方法,但当有重载时很重要)。该函数的签名仍然是 [Object]。(即使签名是 [TemporalQuery],我也怀疑这会有所帮助,因为在这里不会调用 Java 编译器,但我可能错了。)

说了这么多,我确信,在当前的情势下,要实现您想要的功能,唯一的方法就是通过那个古老的reify

(let [formatter java.time.format.DateTimeFormatter/BASIC_ISO_DATE]
  (.parse formatter
          "20200202"
          (reify java.time.temporal.TemporalQuery
            (queryFrom [_ ^java.time.temporal.TemporalAccessor temporal]
              (java.time.LocalDate/from temporal)))))
by
看来我的其他评论——这个功能真的快来了。
...