在 Clojure 中实现数据模型似乎有多种方法:
(type ^{:type ::mytype} {:fieldname 1})
get
将映射中不存在的键抛出异常,而不是静默返回 nil
)我们已经到了 map /列表不再适合我们的地步——我们遇到了很多前置条件/后置条件可以轻松捕获的错误,但需要很长时间才能找到其他的(而且它是很难为接受嵌套映射/列表/向量的函数编写有效的前置/后置条件)——但我们不确定从上述哪个中进行选择。
我们有三大目标:
我们如何利用 Clojure 的力量来帮助我们?
最佳答案
Clojure 文化强烈支持原始数据类型。理所当然的。但是显式类型可能很有用。当你的普通数据类型变得足够复杂和具体时,你基本上有一个没有规范的隐式数据类型。
依赖构造函数。 以 OOP 的方式,这听起来有点脏,但构造函数只不过是一个可以安全方便地创建数据类型的函数。普通数据结构的一个缺点是它们鼓励动态创建数据。因此,我尝试直接组合我的数据,而不是调用 (myconstructor ...)。如果我需要更改基础数据类型,则有很大的错误可能性以及问题。
记录是甜蜜点。 由于对原始数据类型大惊小怪,很容易忘记记录可以做很多 map 可以做的事情。可以以相同的方式访问它们。您可以对它们调用 seq。你可以用同样的方式解构它们。绝大多数需要 map 的函数也将接受记录。
元数据不会拯救你。 我对依赖元数据的主要反对意见是它没有反射(reflect)在平等上。
user> (= (with-meta [1 2 3] {:type :A}) (with-meta [1 2 3] {:type :B}))
true
这是否可以接受取决于您,但我担心这会引入新的微妙错误。
其他数据类型选项:
协议(protocol)非常有用,尽管它们感觉有点偏离(函数+数据)范式。如果您发现自己在创建记录,您也应该考虑定义协议(protocol)。
编辑 :我发现了之前对我来说并不明显的纯数据类型的另一个优势:如果您正在做 Web 编程,纯数据类型可以有效且轻松地转换为 JSON 和从 JSON 转换。 (执行此操作的库包括 clojure.data.json、clj-json 和我最喜欢的 cheshire)。对于记录和数据类型,这项任务相当烦人。
关于clojure - 实现数据模型以防止常见错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7905547/