在Clojure中似乎有多种方法来实现数据模型:
(type ^{:type ::mytype} {:fieldname 1})
get
来自地图的不存在的键会引发异常,而不是静默返回nil
)我们已经达到了地图/列表不再适用于我们的程度 - 我们遇到了很多错误,前置条件/后置条件很容易被捕获,但是需要花费很长时间来追捕(并且很难为接受嵌套地图/列表/向量的函数编写有效的前/后条件) - 但我们不确定上述哪一个可供选择。
我们有三个主要目标:
我们如何利用Clojure的力量来帮助我们?
答案 0 :(得分:4)
Clojure文化强烈支持原始数据类型。理所当然。但显式类型可能很有用。当您的纯数据类型变得足够复杂和具体时,您实际上有一个没有规范的隐式dataype。
依赖于构造函数。这听起来有点脏,以OOP的方式,但构造函数只不过是一个安全方便地创建数据类型的函数。普通数据结构的缺点是它们鼓励动态创建数据。所以,我没有调用(myconstructor ...),而是尝试直接编写我的数据。如果我需要更改基础数据类型,则存在很大的错误可能性以及问题。
记录是最佳选择。由于对原始数据类型的所有大惊小怪,很容易忘记记录执行了很多地图可以做的事情。它们可以以相同的方式访问。你可以打电话给他们seq。你可以用同样的方式去构造它们。期望地图的绝大多数函数也会接受记录。
元数据不会拯救你。我依赖元数据的主要反对意见是它没有反映在平等中。
user> (= (with-meta [1 2 3] {:type :A}) (with-meta [1 2 3] {:type :B}))
true
这是否可以接受取决于你,但我担心这会引入新的微妙错误。
其他dataype选项:
协议是非常有用的,即使它们有点偏离(函数+数据)范例。如果您发现自己正在创建记录,则还应考虑定义协议。
编辑:我发现普通数据类型的另一个优点是我之前没有明白过:如果你正在进行Web编程,那么普通数据类型可以高效,轻松地转换为JSON和从JSON转换。 (这样做的图书馆包括clojure.data.json,clj-json和我最喜欢的,柴郡)。对于记录和数据类型,任务更加烦人。
答案 1 :(得分:1)
能够编写适用于地图和列表的函数真的很方便,通过切换到类和协议来放松它会是一种耻辱。毕竟最好在一种类型上拥有一百个功能。切换到协议或记录会有点沉重。例如,它会在调试时阻止你(debug (map :rows (get-state))
。
元数据是添加“足够类型”的好方法,可以让您的数据在需要它的地方更安全,而不会丢失其他代码库中的好处。我会建议选择2