在 Clojure 中重写一系列 if 语句



也许只是晚上太晚了,但我似乎无法弄清楚这一点。我正在创建看起来像这样的东西

(defn new-psf
  [props]
  (let [psf (Psf.)]
    (if (contains? props :pageLn)
      (.setPageLn psf (props :pageLn)))
    (if (contains? props :pageNum)
      (.setPageNum psf (props :pageLn)))
    (if (contains? props :includedSources)
      (doseq [s (props :includedSources)]
        (.add (.getIncludedSources psf) s)))
    psf))

现在这看起来很丑陋,我不得不认为在重复模式中有一种更干净的方法。似乎没有一个 cond* 函数适合。我自己对宏不够好,无法创建新的东西。

任何人都对宏有任何想法,可以让我做这样的事情:

(defn new-psf
  [props]
  (let [psf (Psf.)]
    (condd (partial contains? props)
      :pageLn (.setPageLn psf (props :pageLn))
      :pageNum (.setPageNum psf (props :pageNum))
      :includedSources (doseq [s (props :includedSources)]
                         (.add (.getIncludedSources psf) s)))
    psf))

似乎conddcondp几乎一样?

(defn new-psf
  [props]
  (let [psf (Psf.)]
    (condp (contains? %2 %1) props
      :pageLn (.setPageLn psf (props :pageLn))
      :pageNum (.setPageNum psf (props :pageNum))
      :includedSources (doseq [s (props :includedSources)]
                         (.add (.getIncludedSources psf) s)))
    psf))

您甚至可以在 condp 中使用很少有用的 :>> 语法,并进行一些更改:

(defn new-psf
  [props]
  (let [psf (Psf.)]
    (condp (get %2 %1) props
      :pageLn :>> #(.setPageLn psf %)
      :pageNum :>> #(.setPageNum psf %)
      :includedSources #(doseq [s %]
                         (.add (.getIncludedSources psf) s)))
    psf))
如果我

没看错的话,无论第一个if测试失败还是成功,以下条件仍在测试?

听起来像是cond->的工作!与condp不同的是,它不会将评估短路到第一场比赛。

(defn with-page-ln [psf v]
  (.setPageLn psf v)
  psf)
(defn with-page-num [psf v]
  (.setPageNum psf v)
  psf)
(defn with-included-sources [psf v]
  (doseq [s v]
    (.add (.getIncludedSources psf) s))
  psf)
(defn new-psf
  [props]
  (cond-> (Psf.)
          (contains? props :pageLn)          (with-page-ln (props :pageLn))
          (contains? props :pageNum)         (with-page-num (props :pageLn))
          (contains? props :includedSources) (with-included-sources (props :includedSources)))

我不确定你的 Psf 类是什么,所以让我们在一个熟悉的类上执行此操作

(def frame (doto (new javax.swing.JFrame) 
                 (.setContentPane (javax.swing.JPanel.))))

属性地图

(def props {:title "test" 
            :background java.awt.Color/blue 
            :buttons ["foo" "bar" "baz"]})

您可以使用地图代替一系列if

(def option-application 
       {:title (fn [x v] (.setTitle x v)) 
        :background (fn [x v] (.setBackground (.getContentPane x) v))
        :buttons (fn [x v] (doseq [btn v] (.add x (javax.swing.JButton. btn))))})

并根据props申请

(doseq [[k v] props] ((k option-application) frame v))

让我们看看我们美丽的框架

(doto frame (.pack) (.setVisible true))

如果 props 中缺少一个键,则永远不会调用它在选项应用程序中的相应操作。如果顺序很重要,请使用数组映射。

请注意,仍然有很多重复,因为对于每个键,我都会包装一个名称相似的二传器。 跷跷板使用反射来处理所有这些问题。请参阅那里的apply-options,它应该足够通用,可以在您的类中使用。跷跷板还有一个您可能想借用的cond-doto

最新更新