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

欢迎!请查看关于页面,了解更多关于这个平台的信息。

+2
Clojure
已关闭

使用Java方法引用,以下代码可以正常工作(此代码取自java.time.LocalDate)

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

parse方法的第二个参数是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).

无法将class user$eval2266$invokeLocalDate_from2268转换为class java.time.temporal.TemporalQuery

这视为错误还是故意为之?如果是有意为之,关于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 IFns将隐式转换为适当类型的接口(或者在let绑定中可以请求显式强制转换)。这是通过invokedynamic完成的,这在本质上与Java lambda编译中使用的机制相同(但我们将使用一组固定的适配器目标,而不是动态生成合成lambda方法)。

新的方法值作为IFns实现,因此可以自动加入到这个中,但如您所想象的那样,将Java方法包装到Ifn中然后将其适配回方法引用并不是最佳选择。幸运的是,我们可以在编译器中识别这种情况并直接适配原始方法。

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

太棒了!谢谢 Alex
0

Clojure中的方法值,本身就是值。这是创建一个使用Java方法恰当重载的lambda函数的语法糖。

Java中的方法引用是一个语法糖,用于在特定上下文中创建正确的东西。你不能只是获取LocalDate::from的值 - 你必须将它放入Java编译器可以确定你确切想要什么的上下文中。

你的例子更像是Java,而不是Clojure。它是Java编译器解析所有签名并确定它们兼容,从而使得你可以以这种方式使用...::from

既然你只是调用parse函数,使用而不是时没有多大意义。

(^[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
好像我的其他评论提到了 - 这项功能即将推出。
...