Clojure:从Map创建记录时确保数据完整性?

eri*_*cky 1 clojure

我正在学习Clojure并享受它,但发现记录中的不一致让我感到困惑:为什么默认的地图构造函数(map-> Whatever)在创建新记录时检查数据完整性?例如:

user=> (defrecord Person [first-name last-name])
#<Class@46ffda99 user.Person>
user=> (map->Person {:first-name "Rich" :last-name "Hickey"})
#user.Person {:first-name "Rich" :last-name "Hickey"}
user=> (map->Person {:first-game "Rich" :last-name "Hickey"})
#user.Person {:first-game "Rich" :first-name nil :last-name "Hickey"}
Run Code Online (Sandbox Code Playgroud)

我相信Map不需要定义Record定义中的所有字段,也允许包含不属于Record定义的额外字段.另外我理解我可以定义自己的构造函数来包装默认构造函数,然后我认为:post可以使用条件来检查正确(和全面)的记录创建(还没有成功地使它工作).

我的问题是:在Map构建记录期间是否有一种惯用的Clojure方法来验证数据?而且,这里有关于唱片的遗漏吗?

谢谢.

glt*_*lts 5

我认为你的全面性要求已经非常具体,所以我所知道的任何内置都没有涵盖这一点.

你现在可以做的一件事就是使用clojure.spec来s/fdef为你的构造函数提供一个函数(然后对它进行检测).

(require '[clojure.spec.alpha :as s]
         '[clojure.spec.test.alpha :as stest])

(defrecord Person [first-name last-name])

(s/fdef map->Person
  :args (s/cat :map (s/keys :req-un [::first-name ::last-name])))

(stest/instrument `map->Person)

(map->Person {:first-name "Rich", :last-name "Hickey"})
(map->Person {:first-game "Rich", :last-name "Hickey"})  ; now fails
Run Code Online (Sandbox Code Playgroud)

(如果定义了规格::first-name,::last-name也会检查规格.)