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

欢迎!请查阅关于页面获取更多有关如何使用本站的信息。

0
Spec

大家好,我来报告我认为是本周第二次的spec仪表件上的问题。

如果这已被报告为错误,我深表歉意,但基本上我无法理解/预料到最后一次调用会触发错误 - ::id-map spec最终并不需要在::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

当对一个map进行检查以查看其与规范的一致性时,它会做两件事 - 检查是否包含所需的属性,以及检查每个已注册的键都有符合规范的价值。我们稍后会在哪里看到可选属性的有用之处。 请注意,所有属性都是通过键进行检查的,而不仅仅是列在 :req 和 :opt 键中的那些。 因此,裸露的 (s/keys) 是有效的,并且会在不检查哪些键是必需的还是可选项的情况下检查map的所有属性。

以下为我的强调

果不其然,的确如此!学到了:D

你知道这个背后的原理吗?看起来`s/keys`应该允许“限制”你想要检查的范围——也就是说,只需检查这些键——但是检查却是针对所有键进行的吗?
我认为Alex可能更适合对此进行评论,但我的理解是,限定规范名称是为了给全局名称提供全局含义,而`s/keys`是为了识别是否需要特定的键(:opt基本上用于文档目的,表示“我可能也会使用这些键”)。必要性是与名称的全局含义正交的。

请注意,对于:req-un / :opt-un不成立,因为这些键在映射中是非限定的,没有全局含义——只由`s/keys`中名称的限定提供(与关联的限定规范名称相关联)。
> 必要性是与名称的全局含义正交的。

感谢你的解释,这正是我所缺少的。全局的东西确实会让孤立的事物更难进行推理(个人看法,可能很显而易见)。我现在明白为什么像`spec2`中的`select`这样的东西会出现了。
你可能会发现阅读规范原理和指南对解答这些问题有所帮助

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