2011-10-07 3 views
9

안녕 얘들 강력한 데이터 API를 구축하는 방법 : 나는, 경우에 잘못 입력 이름이 키 맵을 ...- 내 Clojure의 애플 리케이션이 구조적으로 인해 데이터 API의 부족으로 매우 빠르게 결합받을 것을 발견, 예외가 발생하거나 오류가 발생합니다. 또한리스트를 파괴 할 때 실수를하는 것이 쉽다는 것을 알 수 있습니다. (예를 들어 목록의 잘못된 부분을 파헤쳐 버릴 수도 있습니다) .....어떻게 Clojure의에

일반적으로 자바 세계에서 제공되는 IDE 최소한의 정렬되지 않은 데이터 객체에서 나오는 "올바른"데이터입니다. 그러나 clojure 맵 전달은 이와 반대되는 패러다임 인 것 같습니다.

타입 시스템이나 ide 코드 완성이 없을 때 clojurians은 어떻게 방어합니까?

답변

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 
을 "잘못을 Destructuring 목록의 일부 "유형 문제는 목록에서"사람 "과 같은 것을 인코딩하려고 시도했을 때 올 수 있습니다. "우편 번호는 '사람 목록'의 3 번 위치에있는 '주소'목록의 네 번째 요소와 같은 것을 기억해야합니다.

'고전'리스프에서 당신이 접근 자 함수를 작성하여, Clojure에 당신이 기록을 사용할 수있는 해결 있습니다.

Typos는 프로그래밍 언어에서 문제를 일으킬 수 있습니다. 가능한 한 빨리 그 (것)들을 붙잡는 것을 시도하십시오.

자동 완성 기능이있는 Java IDE는 사용자가 입력하는 동안 오타가 발생할 수 있으며 정적으로 입력 된 언어는 컴파일 할 때 많은 오류를 잡아 내지 만 동적 언어에서는 런타임까지 찾을 수 없습니다. 어떤 사람들은 이것을 파이썬, 루비 등을 포함한 동적 언어의 단점이라고 생각하지만, 프로그래머들은 상당수의 프로그래머들이 IDE 자동 완성 및 컴파일 시간 오류의 손실보다 더 많은 이득을 얻고 코드를 저장하는 것이 더 중요하다고 생각합니다.

원리는 두 경우 모두에서 동일 : 이전 예외는 더 나은, 원인을 찾을 통해 웨이드 적은 코드가 있기 때문에. 이상적으로 스택 트레이스는 오타로 곧바로 이끌 것입니다. Clojure에서 레코드 및 접근 자 함수를 사용하면 이러한 이점을 얻을 수 있습니다.

+1

'크기'라는 레코드 필드가 없어도됩니다. '(.size rec) '를 호출하면 java.util에 정의 된 * method *'size'가 호출됩니다.콜렉션 (Clojure) '이 가지고있는 모든 인터페이스의 모든 무효 메소드에 대해서도 마찬가지이다. –

+0

@Jouni 예, 사용할 수없는 17 개의 이름이 있습니다. 'size','count','values','meta'는 아마도 가장 골치 아플 수 있습니다. 예약어로 취급하고 사용하지 않거나 자체 데이터 API를 작성해야합니다. AFAIK. –