16

我正在关注clojure.spec 指南。我知道在使用 clojure.spec/keys 时可以声明必需和可选属性。

我不明白可选是什么意思。对我来说 :opt 什么也没做。

(s/valid? (s/keys :req [:my/a]) {:my/a 1 :my/b 2}) ;=> true

(s/valid? (s/keys :req [:my/a] :opt []) {:my/a 1 :my/b 2}) ;=> true

该指南承诺向我解释这一点,“我们稍后会看到可选属性在哪里有用”,但我找不到解释。我可以声明禁止键吗?或者以某种方式声明一组有效键等于 :req 和 :opt 中的键?

4

2 回答 2

12

这是一个非常好的问题,clojure.spec API给出了(公认的、简短且不令人满意的)答案:

:opt 键用作文档,并且可以由生成器使用。

如果地图包含额外的(我认为这是“禁止”的意思)密钥,我认为你不能使用这种方法使地图无效。但是,您可以使用此规范来确保 ::bad-key 不存在:

(s/def ::m (s/and (s/keys :req [::a]) #(not (contains? % ::bad-key))))
(s/valid? ::m {::a "required!"})                        ; => true
(s/valid? ::m {::a "required!" ::b "optional!"})        ; => true
(s/valid? ::m {::a "required!" ::bad-key "no good!"})   ; => false

您可以使用此规范将键的数量限制为您想要的集合:

(s/def ::r (s/and (s/keys :req [::reqd1 ::reqd2]) #(= (count %) 2)))
(s/valid? ::r {::reqd1 "abc" ::reqd2 "xyz"})              ; => true
(s/valid? ::r {::reqd1 "abc" ::reqd2 "xyz" ::extra 123})  ; => false

尽管如此,处理此 IMO 的最佳方法是简单地忽略存在您不关心的关键礼物。

希望随着规范的成熟,这些好东西会被添加。或者,也许他们已经在那里(它正在迅速变化)而我根本不知道。这是 clojure 中一个非常新的概念,因此我们大多数人都有很多东西要学习。

更新 - 2016 年 12 月我只是想重新审视这 6 个月以来的写作。看起来我最初关于忽略您不关心的键的评论是首选方法。事实上,在我两周前参加的 clojure/conj 会议上,Rich 的主题演讲专门讨论了从功能级别到应用程序级别的所有软件级别的版本控制概念。他甚至在演讲中特别提到了不允许使用密钥的概念,这可以在 youtube上找到。他说它是有意设计的,因此只能指定所需的密钥。禁用键确实没有什么好的目的,应该谨慎行事。

关于:opt密钥,我认为原始答案仍然很好——它是文档,实际上,它允许生成这些可选指定的密钥:

(s/def ::name #{"Bob" "Josh" "Mary" "Susan"})
(s/def ::height-inches (s/int-in 48 90))
(s/def ::person (s/keys :req-un [::name] :opt-un [::height-inches]))

(map first (s/exercise ::person))

; some generated data have :height-inches, some do not
({:name "Susan"}
 {:name "Mary", :height-inches 48}
 {:name "Bob", :height-inches 49}
 {:name "Josh"}
于 2016-06-30T19:24:06.813 回答
-3

关于可选键的要点是,如果它们出现在地图中,则将验证该

于 2016-06-30T21:25:48.753 回答