clojure.spec中的禁用密钥

clojure.spec中的禁用密钥,clojure,clojure.spec,Clojure,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 指南承诺会向我解释这一点,“我们稍后会看到可选属性在哪里有用”,但我找不到解释。我可

我正在跟踪调查。我理解在使用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中的密钥?

这是一个非常好的问题,并且给出了(已授予、简短且不令人满意的)答案:

: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
尽管如此,处理这件事的最好办法,还是简单地忽略一件你不在乎的关键礼物

希望随着规范的成熟,这些好东西会被添加。或者,也许他们已经在那里了(变化很快),而我对此一无所知。这在clojure中是一个非常新的概念,所以我们大多数人都有很多东西要学习

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

关于
: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"}

关于可选键的一点是,如果值出现在不真实的地图中

,则将验证该值。该值将被验证。如果该键不是必需的或可选的,则该值将根本不会被验证。我并不是说对于所需的键,该值没有被验证“此外,所有命名空间限定键的值都将通过任何注册规范进行验证(可能会被解构)。(Docstr.of
s/keys
)哎哟,这在我的脑海中是如此清晰。将保留答案作为参考。谢谢“不允许使用密钥真的没有什么好处,应该谨慎行事。”嗯,我必须观看演讲才能在上下文中听到这一点,但是,比如说,检查密码字段是否没有从函数中泄漏出来呢?我想问题是,除了显式密钥外,你不能真正确保你没有以其他方式泄露它,但是说检查明显的内容没有什么好的目的似乎有点言过其实,不是吗?所以我听了演讲。我明白规范是关于你能做什么,而不是你不能做什么。但他并没有确切地说,忽视它是首选的方式。他说,这是两种首选方式之一,另一种是“制定政策”。如果我理解正确,我可以做几件事来阻止增长:1)定义一个单独命名的规范,与“忽略”规范不同,后者使用您显示的方法禁止使用密钥,我现在可以使用,可能永远使用,或者稍后删除,2)编写独立的检查程序。他实际上也提到了我的案例:也许你应该使用选择键。这里还有另一个需要考虑的案例:我正在解析二进制协议中的数据。如果数据头中的一个键与某个值匹配,则应该从头后面的位中解析出一个附加字段。但是,如果报头与该值不匹配,则后续位被消耗到该可选额外字段中将非常糟糕。在这种情况下,在我看来,我确实希望在这种情况下禁止使用该密钥,因为我想知道我是否解析了错误的数据包。(我要补充的是,可选密钥的值也可以是nil,但我仍然需要强制它要么为nil,要么不存在。)