请分享您的想法,参加 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).

不能将类用户$eval2266$invokeLocalDate_from2268转换为类java.time.temporal.TemporalQuery(用户$eval2266$invokeLocalDate_from2268在加载器clojure.lang.DynamicClassLoader的匿名模块中;java.time.temporal.TemporalQuery在加载器'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 的 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
查看我的另一条评论——这个功能实际上即将推出。
...