【问题标题】:Calling a list of methods on a Java object using Clojure使用 Clojure 调用 Java 对象的方法列表
【发布时间】:2016-07-11 15:04:25
【问题描述】:

我有一个要转换为不可变 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->map返回期望值:

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

reduce-kv 只返回我拥有的最后一个值:

150.0

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

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

reduce-kv 函数返回一个 double 时,.build 的以下调用失败了

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

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

【问题讨论】:

    标签: clojure clojure-java-interop


    【解决方案1】:

    虽然 Clojure 符号 act as functions,但它们不以任何方式与同名函数连接:

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

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

    ['.latitude '.longitude '.altitude]
    
    ->
    
    [(memfn latitude val) (memfn longitude val) (memfn altitude val)]
    

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

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

    【讨论】:

    • 目前没有(memfn foo)优于#(.foo %)的情况
    • 谢谢你们,这行得通!请注意:为了完全匹配我的问题,创建的函数采用两个参数(构建器实例和要设置的值)。因此它是(memfn latitude val)#(.latitude %1 %2)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多