2011-10-07 25 views
9

嗨,大家好:我发现我的clojure应用程序由于缺少数据API而在结构上非常迅速地耦合......-我的地图上键名称错误,导致抛出异常或错误。我还注意到,在解构列表时(例如,也许你在解构列表的错误部分),容易犯错误......如何在clojure中构建强大的数据apis

来自java世界,通常我使用我的IDE来帮助我获得从最小的,无序的数据对象中获取“正确的”数据---但clojure映射传递似乎与此相反。

clojurians在没有类型系统或ide代码完成的情况下如何防守编码?

回答

5

为你的“模式”(键值和值的类型等)编写验证器函数,然后在代码的前后条件中使用thm--因为它们的语法很少被人知道,所以这里是一个快速复习:

(defn foo [x y] ; works with fn too 
    {:pre [(number? x) (number? y)] 
    :post [(number? %) (pos? %)]} 
    (+ (* x x) (* y y))) 

他们依靠assert,因此可以被禁用。 (doc assert)了解更多详情。

+0

自发布以来,core.typed已发布,也可以执行相同的操作http://typedclojure.org/ – Ben

5

也许您在查找记录?

(require '[clojure.set :as cset]) 

(defrecord Person [name age address phone email]) 

    ;; Make a keyword-based constructor to verify 
    ;; args and decouple ordering. 
(let [valid #{:name :age :address :phone :email}] 
    (defn mk-person[& args] 
    (let [h (apply hash-map args) 
      invalid (cset/difference (set (keys h)) valid)]  
     (when-not (empty? invalid) 
     (throw (IllegalArgumentException. (pr-str invalid)))) 
     ; any other argument validation you want here 
     (Person. 
     (:name h) (:age h) (:address h) (:phone h) (:email h))))) 

=> (def p (mk-person :name "John" :email "[email protected]")) 
#:user.Person{:name "John", :age nil, :address nil, :phone nil, 
       :email "[email protected]"} 

现在,您可以通过访问与功能(除外)或关键字(不除外)的数据选择是否为正确输入名称例外。

=> (.fax p) 
java.lang.IllegalArgumentException: 
    No matching field found: fax for class user.Person 
=> (:fax p) 
nil 

此方法要求您避免与现有方法冲突的字段名称。 (从@Jouni见注释)。

或者,您也可以通过使用查找关键字和检查无效密钥的访问功能绕过字段名限制:

(defn get-value [k rec] 
    (let [v (k rec ::not-found)] 
    (if (= v ::not-found) 
     (throw (IllegalArgumentException. (pr-str k))) 
    v))) 

=> (get-value :name p) 
"John" 
=> (get-value :fax p) 
IllegalArgumentException: :fax 

“解构错列表的一部分“ - 类型问题可能来自于尝试在列表中编码像”人“这样的东西;那么你需要记住一些东西,比如“邮政编码是”人物列表“中第三位'地址'列表中的第四个元素。

在'古典'Lisp中,你可以通过编写存取函数来解决这个问题,在Clojure中你可以使用记录。

错别字会导致任何编程语言的问题,您所能做的最好的办法就是尽早赶上它们。

具有自动完成功能的Java IDE可能会在输入时遇到一些拼写错误,而静态类型语言在编译时会捕获其中的许多错误,但是在动态语言中,直到运行时才会找到它们。有些人认为这是动态语言(包括Python,Ruby等)的缺点,但考虑到它们的普及,不少程序员认为获得的灵活性和保存的代码比丢失IDE自动完成和编译时错误更重要。

两种情况下的原理都是一样的:以前的例外情况会更好,因为要查找原因的代码越少越好。理想情况下,堆栈跟踪会导致您直接输入错字。在Clojure中,记录和存取函数为您提供了这些功能。

+1

虽然没有名为'size'的记录字段。调用'(.size rec)'将调用java.util中定义的* method *'size'。集合“,对于Clojure记录所有接口中的所有空方法也是如此。 –

+0

@Jouni是的,有17个名字你不能使用; 'size','count','values'和'meta'可能是最麻烦的。你必须把它们当作保留字并避免使用它们,或者编写你自己的数据API。据我所知。 –