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

欢迎!请访问关于页面,了解更多关于如何使用本站的信息。

0
规范

嗨,我正在这里报告我认为是一周内的第二个与规范工具相关的怪异现象。

如果这已经作为 bug 报告过,我表示歉意;但基本上,我不明白为什么最后一个调用会引发错误 -::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

当对一个映射进行检查时,它会执行两件事情 - 检查是否包含了必要的属性,以及检查每个已注册键是否有符合规范的价值。我们稍后会看到可选属性可以有何用途。 注意,所有属性都通过键进行检查,而不仅仅是那些列在 :req 和 :opt 键中的属性。 因此,一个简单的(s/keys)是有效的,它将检查映射的属性,而无需检查哪些键是必需的或可选的。

(我强调的部分)

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

你知道围绕这个问题的原因吗?看起来`s/keys`可以“限制”你想要检查的范围——也就是说,只检查这些键——但检查实际上是在所有这些键上进行的吗?
by
我认为Alex可能更适合对此进行评论,但我的理解是,有资格的Spec名称是为了给全局名称赋予全局意义,而`s/keys`是用来标识是否需要特定的键的(`:opt`本质上是出于文档目的,表示“我也可能使用这些键”)。需要的概念与名称的全局意义是正交的。

注意,这对于`:req-un` / `:opt-un` 不是真的,因为这些键在映射中是无资格的,不具有全局意义——它们只有赋值给`s/keys`中名称的资格(到相关的有资格的Spec名称)时的意义。
by
> 需要的概念与名称的全局意义是正交的。

感谢你的解释,这正是我所缺乏的。全局事物确实会使孤立的事物更难推理(个人看法,也许很明显)。我现在明白为什么`spec2`中的`select`这类问题会出现。
by
你可能会发现阅读规范原因和指南对填补一些这些问题有所帮助。

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