2011-10-07 43 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。據我所知。 –

相關問題