使用 Clojure 在 Java 对象上调用方法列表

Calling a list of methods on a Java object using Clojure

我有一个要转换为不可变 Java POJO 的值列表。 Java POJO 使用构建器模式生成。

我的列表是:

[49.0 11.1 150.0]

在 Java 中,我的 POJO 将像这样构建:

Position.builder().latitude(49.0).longitude(11.1).altitude(150.0).build()

我想在 Clojure 中创建它,我首先 zipmap 需要使用的方法的值,然后我可以 reduce-kv 一切到我需要的 Java 值:

(defn poslist->map [list]
      (zipmap ['.latitude '.longitude '.altitude]
              list))

(.build (reduce-kv #(%2 %1 %3) 
                   (pkg.Position/builder)
                   (poslist->map list)))

我现在的问题是我没有得到我期望的结果。函数poslist->mapreturns期望值:

{.latitude 49.0, .longitude 11.1, .altitude 150.0}

但是 reduce-kv 只是 returns 我拥有的最后一个值:

150.0

为什么我不取回可以应用 .build 方法的构建器?我曾预计 reduce-kv 与以下代码具有相同的结果 returns 我所期望的结果:

(.build (.altitude (.longitude (.latitude (pkg.Position/builder) 150.0) 11.1) 49.0))

并且作为 reduce-kv 函数 returns 以下对 .build 的双重调用失败

No matching field found: build for class java.lang.Double

顺便说一句:我将方法映射到列表值的原因是,我必须设置的实际字段列表比示例中的更长。我在保留基本问题的同时精简了示例以提高可读性。

虽然 Clojure 符号 act as functions,但它们与同名函数没有任何关联:

> ('.add (java.util.ArrayList.) 1)
1
> ('first [1 2 3])
nil
> ('conj [1 2] 3)
3

所以问题基本上是根本没有调用 java 方法。要修复它,请使用 memfn:

包装您的 iterop 方法
['.latitude '.longitude '.altitude]

->

[(memfn latitude val) (memfn longitude val) (memfn altitude val)]

或者,正如@noisesmith 建议的那样,使用 clojure 函数:

->

[#(.latitude %1 %2) #(.longitude %1 %2) #(.altitude %1 %2)]