2016-06-30 11 views
8

我正在关注clojure.spec guide。我知道使用clojure.spec/keys时可以声明必需的和可选的属性。clojure.spec中的禁止键

我不明白什么是可选的。对我来说:选择不做任何事情。

(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?

回答

8

这是一个很好的问题,以及clojure.spec API给出了(当然,短期和不令人满意的)答案:

的:选择键作为文档和 可通过发生器使用。

我不认为你可以使地图失效,如果它包含一个额外的(这就是你所说的“禁止”我认为)的意思是使用这种方法的关键。但是,你可以使用这个规范来确保::坏键不存在:

(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的主题演讲特别提到了从功能层面到应用层面的所有软件版本的概念。他甚至在谈话中特别提到禁止键的概念,可以找到on 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"} 
+0

“禁止密钥确实没有任何好的目的,并且应该谨慎对待。”嗯。我将不得不观看这个演讲,以便在上下文中听到,但是如何检查密码字段不会泄漏出某个函数呢?我想问题的关键是,除了明确的密钥之外,你不能确保你不以其他方式泄漏它,但似乎有点夸大地说,检查显而易见的东西没有好的目的,不是吗? – neverfox

+0

所以我听了这个讲话。我看到规范是关于你能做什么的,而不是你做不到的。但他并没有确切地说,忽视它是首选的方式。他说这是两种首选方式之一,另一种是“有政策”。如果我的理解正确的话,我可以做一些事情来阻止增长:1)定义一个单独命名的规范,从“只是忽略”一个,不允许使用你显示的方法的密钥,我现在可以使用,也许保留永远使用,或稍后放下,2)编写独立的检查程序。他实际上也解决了我的问题:也许你应该使用选择键。 – neverfox

-3

有关可选键的一点是的值将被验证,如果它们出现在地图中

+1

这是不真实的。无论如何,该值都将被验证。 –

+0

如果该键既不是必需键也不是可选键,则该值根本不会被验证。我并不是要求所需的密钥的值没有验证 – DanLebrero

+1

“此外,* all *命名空间限定的密钥的值将通过任何注册规范验证 (并可能解构)。” ('s/keys'的Docstr。) –