对于clojure.spec,是否有一种方法可以为嵌套映射定义更“人类可读的”规范?下面的内容读得不太好:
(s/def ::my-domain-entity (s/keys :req-un [:a :b])
(s/def :a (s/keys :req-un [:c :d]))
(s/def :b boolean?)
(s/def :c number?)
(s/def :d string?)考虑到协调实体的形状类似于
{:a {:c 1 :d "hello"} :b false}
我的抱怨是,如果规范有任何类型的嵌套映射或任何深结构的…,就很难(呃)读取它。因为您在文件中上下追逐键,而它们并不是“就位”声明。
为了进行比较,类似于模式的东西允许一个更加可读的嵌套语法,该语法密切反映实际的数据形状:
(m/defschema my-domain-entity {:a {:c sc/number :d sc/string} :b sc/bool})
这能在clojure.spec中完成吗?
发布于 2017-02-20 14:11:15
规范的一个价值主张是,它不试图定义一个实际的模式。它不将实体的定义绑定到其组件的定义。引用规范原理
大多数用于指定结构的系统将密钥集的规范(例如,映射中的键、对象中的字段)与这些键指定的值的规范混为一谈。也就是说,在这种方法中,映射的模式可能会说:a-key的类型是x-type,而:B-key的类型是y-type。这是僵化和冗余的主要来源。 在Clojure中,我们通过动态地组合、合并和构建映射来获得权力。我们通常处理可选和部分数据、不可靠的外部来源产生的数据、动态查询等。这些映射表示相同密钥的各种集合、子集、交叉点和联合,而且在任何使用时,通常都应该具有相同密钥的相同语义。定义每个子集/联合/交叉的规范,然后冗余地声明每个键的语义,这是一个反模式,在最动态的情况下是行不通的。
因此,为了直接回答这个问题,没有,规范没有提供这种类型的规范,因为它是以这种方式专门设计的。为了获得更动态、更可组合、更灵活的规范,您可以在类似模式的定义中权衡某种程度的人的可读性。
虽然这不是您的问题,但是请考虑使用一个系统将实体的定义与其组件的定义分离开来的好处。它是人为设计的,但考虑定义一辆汽车(在这里简单地节省空间,只需使用轮胎和底盘):
(s/def ::car (s/keys :req [::tires ::chassis]))我们只定义一次,我们可以将任何轮胎配置放在上面:
(s/def ::tires (s/coll-of ::tire :count 4))
(s/def ::tire (s/or :goodyear ::goodyear}
:michelin ::michelin))
(s/def ::goodyear #{"all-season" "sport" "value"})
(s/def ::michelin #{"smooth ride" "sport performance"})
(s/def ::chassis #{"family sedan" "sports"})以下是不同的配置,但都是有效的汽车:
(s/valid? ::car {::tires ["sport" "sport" "sport" "sport"]
::chassis "sports"})
(s/valid? ::car {::tires ["smooth ride" "smooth ride"
"smooth ride" "smooth ride"]
::chassis "family sedan"})这是人为的,但清楚地看到,在将组件定义为独立于组件一起形成的内容时具有灵活性。轮胎有自己的规格,它们的规格不是汽车的定义,即使它们是汽车的部件。它更冗长,但更灵活。
https://stackoverflow.com/questions/42346404
复制相似问题