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(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函数将隐式转换为必要的函数式接口

(^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 函数,因此使用 when 没有意义,而不是可以使用的

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

when instead you can use

(.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
请注意我的其他评论 - 这其实是即将到来的。
...