Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从clojure映射使init成为java构建器类的更好方法?_Clojure_Clojure Java Interop - Fatal编程技术网

从clojure映射使init成为java构建器类的更好方法?

从clojure映射使init成为java构建器类的更好方法?,clojure,clojure-java-interop,Clojure,Clojure Java Interop,每个人 我正试着写一个函数来包装clojure 函数将采用如下映射:{:header true:locale“US”},函数将根据映射配置生成器 (defn reader-options [ opts ] (let [ b (CsvReadOptions$Builder.)] (cond-> b (contains? opts :locale ) (.locale (:locale opts)) (contains? opts :header ) (.h

每个人

我正试着写一个函数来包装clojure

函数将采用如下映射:{:header true:locale“US”},函数将根据映射配置生成器

(defn reader-options [ opts ]
  (let [ b (CsvReadOptions$Builder.)]
    (cond-> b
      (contains? opts :locale ) (.locale (:locale opts))
      (contains? opts :header ) (.header (:header opts))
        true (.build ))
  )
)
抱歉,如果要求太多,clojure中是否有更好的方法来实现这一点?因为键在单行中重复工作

      (contains? opts :locale ) (.locale (:locale opts))    
再次感谢您的建议。

您可以在
let
中使用:

(let [{:keys [a b c]} {:a 1 :b false}]
  [a b c])
;; => [1 false nil]
或在函数参数中:

(defn args-demo [{:keys [a b c]}]
  [a b c])
(args-demo {:a 1 :b false})
;; => [1 false nil]
问题是,如果地图中不存在特定的键,它将绑定到
nil
。如果您的值可以有
nil
值,那么它将不起作用

对于非当前值,可以使用一些“标记”值:

(let [{:keys [a b c] :or {a ::absent b ::absent c ::absent}} {:a 1 :b nil}]
  (cond-> {}
    (not= a ::absent) (assoc :a2 a)
    (not= b ::absent) (assoc :b2 b)
    (not= c ::absent) (assoc :c2 c)))
;; => {:a2 1, :b2 nil}
您还可以创建宏:

(defmacro when-key-present
  [k m & body]
  `(let [{:keys [~k] :or {~k ::not-found}} ~m]
     (when (not= ~k ::not-found)
       ~@body)))

(when-key-present a {:a false :b nil}
  (println "a was" a))
;; prints "a was false"

(when-key-present b {:a false :b nil}
  (println "b was" b))
;; prints "b was nil"

(when-key-present c {:a false :b nil}
  (println "c was" c))
;; doesn't print anything
你的职能是:

(defn reader-options [opts]
  (let [builder (CsvReadOptions$Builder.)]
    (when-key-present locale opts
      (.locale builder locale))
    (when-key-present header opts
      (.header builder header))
    (.build builder)))
您甚至可以创建一个宏,该宏假定opts map中的键与应该调用的生成器方法相同,这样您就可以像这样使用它:

(let [builder (CsvReadOptions$Builder.)]
  (doseq [k (keys opts)]
    (set-builder-property builder k opts)))

但这变得越来越神奇,越来越难理解,所以在使用宏之前,我会三思而后行。

在这个问题中,有几个因素存在:

  • 可选参数
  • 可变对象
  • Java互操作
  • 这就是您在每行上复制3次
    locale
    header
    的原因。我想不出一个简单的方法来减少这种重复。如果这是应用程序中的常见模式,则可以编写宏(编译器扩展)以使其更容易。除非代码中经常出现这种情况,否则成本(在复杂性、文档、误解等方面)将大大超过收益

    有点像买一辆新车而不是清洗旧车。除了在极端情况下,成本可能不值得收益


    )()

    理论上,您可以编写一个宏,将其扩展为所需的代码:

    (defmacro defbuilder [fn-name builder-class fields]
      (let [opts (gensym)]
        `(defn ~fn-name [~opts]
           (cond-> (new ~builder-class)
             ~@(mapcat
                (fn [field-sym]
                  (let [field-kw (keyword (name field-sym))]
                    `((contains? ~opts ~field-kw)
                      (. ~field-sym (get ~opts ~field-kw)))))
                fields)
             true (.build)))))
    
    现在,

    将产生:

    (clojure.core/defn options-from-map [G__12809]
      (clojure.core/cond-> (new CsvReadOptions$Builder)
        (clojure.core/contains? G__12809 :header)
        (. header (clojure.core/get G__12809 :header))
        (clojure.core/contains? G__12809 :locale)
        (. locale (clojure.core/get G__12809 :locale))
        ...
        true (.build)))
    
    然而,在实践中,该规范是:

    • 可读性和可维护性较差(有些库大量使用宏,读起来很痛苦),以及
    • 您可能希望为某些方法添加额外的特定处理(例如,将区域设置字符串转换为
      locale
      对象)
    因此,手工编写包装器要好得多——或者,如果只需要在代码中使用一次构建器,则完全省略包装器并使用互操作

    (clojure.core/defn options-from-map [G__12809]
      (clojure.core/cond-> (new CsvReadOptions$Builder)
        (clojure.core/contains? G__12809 :header)
        (. header (clojure.core/get G__12809 :header))
        (clojure.core/contains? G__12809 :locale)
        (. locale (clojure.core/get G__12809 :locale))
        ...
        true (.build)))