2024年Clojure状态调查!中分享您的想法。

欢迎!请查看关于页面了解更多本网站的详细信息。

+10
Collections
重新标记

我在spec方面做很多工作,我经常遇到的一个问题是构造一个具有可选字段的spec对象。

一个常见的模式如下所示

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

然而,这个模式有一个重大问题:如果::optional-field位于spec/keys:opt字段,并且这个字段不可为nil,那么无论哪个不包括可选字段的对象都会根据该spec被认为是无效的,因为这些对象将具有一个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 支持票

被选中
...