大家好:在java中,我们都有使用ide来“遍历”复杂数据类型深度的经验:
dog.getCollar().getCollarTag().getName();
然而,在Clojure中,由于缺乏静态类型,这变得非常简单。我们如何“防御”或反对可能来自嵌套数据结构的复杂事件?
1)对clojure数据结构深度的可取“限制”?
和
2)处理非常深层嵌套的数据结构的常用习惯用法,它可以防止 错误,如误认为地图列表,或未能正确降低/大写变量名称?
请原谅我,如果我在这里听起来有点偏离范例......可能是这样的错误可以通过在REPL中不断测试来有效地抑制。但是,我想知道是否还有其他在编译时确保代码尽可能正确的方法(即单元测试,IDE / emacs插件等)
答案 0 :(得分:6)
关键字是你的朋友
(def my-animals { :dog {:collar {:tag {:name "fido"}}}})
尝试坚持使用地图,因为它们更具有自我描述性
然后先使用线程和..
宏
(-> my-animals :dog :collar :tag :name)
并利用关键字也是在地图中看起来自我的功能这一事实。
当您在具有代码完成功能的IDE中工作时,它会解析代码,然后构建有关该代码的数据,然后解析该数据以生成它的建议。如果你的数据是自我声明的(它可以是“读取”),那么即使没有IDE,你也可以得到它。
ps:这导致关于“代码就是数据”的标准咆哮已经被比我更聪明的人多次表达过了:)
答案 1 :(得分:3)
在REPL中测试函数的正确性是一个好的开始。改进的一个好方法是单元测试,也许还有前后条件的使用(http://objectcommando.com/blog/2010/03/07/design-by-contract-with-clojure/).
使用关键字时,您的示例可以转换为(get-in dog [:collar :tag :name])
。并使用assoc-in
或update-in
进行“修改”。
答案 2 :(得分:2)
有一个很棒的图书馆,我发现在这方面真的很有帮助,这是来自制作棱镜的人的Schema library。它提供了一种为嵌套数据结构添加可选类型的方法,例如您在问题中引用的数据结构。这可以在运行时(或仅在测试时)强制执行,以验证函数的输入。此外,它还可以作为很好的文档,描述函数对其输入的假设(这不是一件小事)。
答案 3 :(得分:1)
链接的getter通常违反了Law of Demeter。在这样做时,您将代码耦合到整个数据结构,这可能是棘手而复杂的。在函数式语言中,clojure使用递归和序列处理更自然地保持简单和惯用。所以:
答案 4 :(得分:1)
How do we "defend" or Clojure against complexites that might arrive from nested data structures?
你做不到。这是这种语言的失败之一。如果你想要静态打字,那么clojure不是你的事。很多人会建议使用嵌套映射,这些映射很慢,根本不提供任何安全性,也不是数据类型。 Map是一种数据类型,嵌套映射不是,它们是伪装对象。就像javascript一样,clojure要求程序员跟踪各种数据的实际内容,因为Clojure中的数据片段是5种不同数据结构的组合,而不是数据结构本身。