Clojure 2024年度调查中分享您的想法!

欢迎!有关此功能的信息,请参阅关于页面。

+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转换为类java.time.temporal.TemporalQuery ; user$eval2266$invokeLocalDate_from2268在未命名的模块中,由clojure.lang.DynamicClassLoader加载器 @37e99783;java.time.temporal.TemporalQuery在java.base模块中,由'bootstrap'加载器加载

你认为这是错误还是故意为之?如果是故意为之,一些关于Clojure方法值与Java方法引用对比的文档也许会有帮助。

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

(**************************************************************************) DateTimeFormatter/.parse (DateTimeFormatter/ofPattern "yyyyMMdd") "20200202" java.time.LocalDate/from)

2 个答案

+3
by

这将在下一个alpha版本中新加入的功能接口强制转换中发挥作用。

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

新方法值表示为IFns,因此可以自动进入这个框架,但可以想象,将Java方法包装为Ifn然后将其转换回方法引用不是最优的。幸运的是,编译器中可以识别这种情况,并直接适配原始方法。

因此,它即将到来!这是1.12故事的一部分。

by
太棒了!感谢Alex
0
by

Clojure中的方法值,嗯,就是值本身。这是创建使用Java方法正确重载的lambda函数的语法糖。

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
看看我的其他评论 - 这个功能即将推出。
...