【发布时间】:2020-07-14 07:49:19
【问题描述】:
我正在编写与外部 Java 库交互的 Clojure 代码。其中一种方法返回 Java Optional 对象。假设它返回Optional<String>,我需要将Optional 对象中的字符串值更改为小写。如果我用 Java 编写代码,我会使用 map 方法:
Optional<String> ret = someObj.someMethod();
ret.map(String::toLowerCase)
.map(...)
.orElse("x");
所以,我需要在 Clojure 中调用 someObj.someMethod() 并且必须做类似的工作。我发现是这样的:Passing a Clojure function as java.util.Function
所以我写了这样的代码:
(defn ^java.util.function.Function jfn [f]
(reify java.util.function.Function
(apply [this arg] (f arg))))
(let [ret (.someMethod someObj)]
(.. ret
(map (jfn (fn [x] (s/lower-case x))))
(map (jfn (...)))
(orElse "x")))
为了将 clojure 函数传递到需要 Java lambda 的地方,我使用了如上定义的jfn。实际上它工作得很好。
但我不确定这是不是最好的方法,因为我必须用 Java 的 Function 包装调用 Java 方法的 clojure 函数。
有没有更好/更简单的方法来做到这一点?如果我们可以直接调用JavaString的toLowerCase方法就更好了。
【问题讨论】:
-
我不确定它是否适合您的用例,但您可以尽早“拆箱”
Optional,并使用some->宏执行类似操作。即使您稍后需要一个带有值的Optional,也可能比执行函数互操作更容易重新装箱该值。 -
@TaylorWood 感谢您的反馈。我认为您的想法是有效的,值得作为答案。
-
我更喜欢你的第一种方法。如果您不喜欢装箱,并且您的函数都是文字,您可以将
jfn设为宏而不是函数:(defmacro jfn [[arg] & body] (reify Function (apply [_# ~arg] ~@body))),然后是(.map ret (jfn [x] (s/lower-case x)))。
标签: java clojure clojure-java-interop