请在2024 State of Clojure 调查!中分享您的想法。

欢迎!请查阅关于页面以了解更多有关如何使用本站的信息。

+10
集合
重新标记

我经常与spec配合使用,一个常见的问题是构建具有可选字段的spec'对象。

一个常见模式可能如下所示

(assoc {::required-field :value}
       ::optional-field (when some-condition
                          :optional-value))

然而,这种模式有一个重大问题:如果::optional-field在场spec/keys :opt字段不可为nil,那么每个省略了可选字段的对象都将根据该规范无效,因为它们将具有nil值而不是省略键。

这种方法的替代方法是使用类似下面的cond->

(cond-> {::required-field :value}
  some-condition (assoc ::optional-field :optional-value))

这种模式远非cond->的唯一用途,但它出现频率较高。我认为这很不好,因为它要求条件一直显示在最上面,而且使用某些函数生成:optional-value时,无法通过nil punning终止,同时仍然生成一个有效值,而不需要额外的流程控制和本地绑定。

此问题的一个更灵活的解决方案是使用if-some,但这种解决方案很啰嗦,当需要同时包含多个可选字段时,会变得难以控制,如下所示。

(let [m {::required-field :value}
      m (if-some [v (produces-optional-value)]
          (assoc m ::optional-field v)
          m)
      m (if-some [v (produces-other-value)]
          (assoc m ::other-field v)
          m)]
  m)

此问题的一个解决方案是函数assoc-some,它类似于assoc,但当给定的值为nil时,它会省略键。这个函数在medley中提供,并被一些所使用

上面的复杂示例,使用assoc-some将如下所示

(assoc-some {::required-field :value}
            ::optional-field (produces-optional-value)
            ::other-field (produces-other-value))

这可能是解决此问题的唯一方法,但我认为这是一个值得考虑的问题。

这是另一个情况,其中命名解决方案不适用,但它似乎遵循类似的模式,例如在farolero中的这段代码(点击查看),这个问题可以通过一个并行函数(除了我的实现之外尚未在野外找到)update-some来解决,该函数将更新一个键的新值,如果该值为nil,则删除该键。

1 答案

+1 点赞

选中
欢迎来到Clojure Q&A,您可以在此处提出问题并从Clojure社区成员获得答案。
...