Clojure 实现数据模型以防止常见错误
在Clojure中实现数据模型似乎有多种方法:Clojure 实现数据模型以防止常见错误,clojure,datamodel,Clojure,Datamodel,在Clojure中实现数据模型似乎有多种方法: 普通内置数据类型(映射/列表/集合/向量) 内置数据类型+元数据——例如:(类型^{:type::mytype}{:fieldname 1}) 内置数据类型+特殊访问器函数(例如,get从映射中提取不存在的密钥会引发异常,而不是静默返回nil) deftype 解构 解除记录 解除协议 我们已经到了映射/列表不再适用于我们的地步——我们遇到了许多前置条件/后置条件很容易捕捉到的错误,但要找出其他错误需要很长时间(并且很难为接受嵌套映射/列表/向
- 普通内置数据类型(映射/列表/集合/向量)
- 内置数据类型+元数据——例如:
(类型^{:type::mytype}{:fieldname 1})
- 内置数据类型+特殊访问器函数(例如,
从映射中提取不存在的密钥会引发异常,而不是静默返回get
)nil
- deftype
- 解构
- 解除记录
- 解除协议
- 编写习惯的Clojure代码
- 避免花费大量时间查找愚蠢的类型错误
- 相信我们能够通过无声地破坏任何东西来更改/重构代码
我们如何利用Clojure的强大功能来帮助我们呢?能够编写在映射和列表上工作的函数真的很方便,如果通过切换到类和协议来实现这一点,那将是一种耻辱。毕竟,一种类型上有一百个函数更好。切换到协议或记录会有点笨手笨脚。例如,它会阻止您在调试时执行
(调试(映射:行(获取状态))
元数据是一种添加“刚好足够类型”的好方法,它可以使您的数据在需要它的地方更安全,而不会失去代码库其余部分的好处
- '内置数据类型+元数据((类型^{:type::mytype}{:fieldname 1}))'
user> (= (with-meta [1 2 3] {:type :A}) (with-meta [1 2 3] {:type :B}))
true
这是否可以接受取决于您,但我担心这会引入新的微妙的bug
其他数据类型选项:
- deftype仅用于创建新的基本或特殊用途数据结构的低级工作。与defrecord不同,它不会带来clojure的所有优点。对于大多数工作来说,它不是必需的,也不是建议的
- 当Rich Hickey引入类型和协议时,他本质上说应该永远首选defrecord
协议非常有用,即使它们感觉有点偏离(函数+数据)范例。如果发现自己创建了记录,也应该考虑定义协议。
编辑:我发现了简单数据类型的另一个优势,这在我之前并不明显:如果你在做web编程,那么简单数据类型可以高效轻松地转换成JSON(用于转换的库包括clojure.data.JSON、clj JSON和我最喜欢的cheshire).对于记录和数据类型,任务要烦人得多。一个Alan Perlis ism不是在一个数据类型上有大约100个函数吗?我在标题中重新格式化了这个例子--不小心把它放在了非LISP括号中!是的,这就是我要说的,信用在哪里?好的,所以我需要弄清楚
defrecord
和defprotocol
,可以忽略defstruct
,不必太担心deftype
。对于clojure程序来说,defrecord
创建java代码有什么关系吗?从某种意义上说,我不想担心拥有java类,但如果clojure想私下使用一个,那就好了?太好了回答,非常简洁。正如您在上所看到的,普通映射也是一个java类,所以defrecord创建java类并不是什么大问题。从我们使用记录的角度来看,它不会有太大的区别——除了构造,它会感觉完全像clojure数据。是的,一定要阅读defrecord Defa协议nd扩展协议。它们背后的逻辑是经过深思熟虑的,我担心的是我不知道这到底意味着什么:在与当前名称空间、给定字段以及可选的协议和/或接口方法同名的包中,为具有给定名称的类动态生成编译字节码。
(来自defrecord文档)