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

欢迎!请参阅 关于页面 了解更多有关此功能的信息。

0
Spec

您好,我想报告我认为是我本周遇到的第二个 specification 工具的怪癖。

如果这已经被报告为错误,我为此表示歉意,但是基本的想法是无法理解/期望最后调用引发错误 -::id-map 规范最后根本不需要检查 ::other

(ns repro-spec.test
  (:require [clojure.spec.alpha :as s]
            [clojure.spec.test.alpha :as st]))

(s/def ::impl any?)
(s/def ::id string?)
(s/def ::other number?)

(s/def ::id-map (s/keys :req [::id]))

(s/fdef delete-impl
  :args (s/cat :impl ::impl
               :id-map ::id-map))

(defn delete-impl [_ id-map]
  (println (str "This deletes " (::id id-map)))
  id-map)

(st/instrument)

(delete-impl {} {::id "test"})
;; prints "This deletes test"

(delete-impl {} {::id "test" ::other "ignore me"})
;; Execution error - invalid arguments to repro-spec.test/delete-impl at (REPL:27).
;; "ignore me" - failed: number? at: [:id-map :repro-spec.test/other] spec: :repro-spec.test/other

是我做错了什么吗?

1 答案

0

这是设计使然,并在文档中有描述:https://clojure.org/guides/spec#_entity_maps

当在映射上检查合规性时,它会做两件事 - 检查必需的属性是否包含,并检查每个注册键都有符合的值。我们稍后会看到可选属性可以有什么用。请注意,ALL 属性都通过键进行检查,而不仅仅是 :req 和 :opt 键中列出的属性。

(强调内容)

的确在那里!学到了!:D

你有没有机会说明一下这个背后的原因?似乎`s/keys`可以“限制”要检查的范围,比如:只检查这些键——但是检查是在所有键上进行的吗?
我认为Alex更合适评论这个问题,但我的理解是,限定的Spec名称旨在赋予全局名称全局意义,而`s/keys`是用来确定特定键是否需要的——(:opt基本上用于文档目的,表明“我可能也会使用这些键”)。必需性与名称的全局意义是正交的。

注意,这对于`:req-un` /`:opt-un`不成立,因为这些键在映射中是不限定的,且没有全局意义——只有`s/keys`中名称限定给它关联的限定Spec名称时的意义。
> 必需性与名称的全局意义是正交的。

感谢你的解释,这是我之前缺失的。全局事物确实会使孤立的事物更难进行推理(个人看法,可能很明显)。我现在明白为什么`spec2`中的`select`会出现了。
阅读规范的理由和指南可能有助于回答这些问题

* https://clojure.org/about/spec
* https://clojure.org/guides/spec
第一个链接很有用,谢谢。
...