(cljs/run - at (JSVM.: all) "한 번 에 하 얀 DataType, Record, Protocol")

5931 단어 clojurescript
머리말
  프로젝트 에서 우 리 는 보통 실제 문제 영역 에 분야 데이터 모델 을 정의 합 니 다. 예 를 들 어 VDOM 을 개발 할 때 자 연 스 럽 게 VNode 데이터 형식 을 정의 하여 관련 데 이 터 를 포장 하고 저장 하 며 조작 하 는 데 사 용 됩 니 다.clj/cljs 는 List, Vector, Set, Map 등 데이터 구 조 를 내장 하고 deftypedefrecord 를 제공 하여 실제 개발 수 요 를 만족 시 킬 수 있 도록 데이터 구 조 를 사용자 정의 할 수 있 습 니 다.
데이터 구 조 를 정의 하려 면 Data Type 과 Record 부터 시작 합 니 다.
  데이터 구 조 를 언급 하면 자 연 스 럽 게 C 언어 중의 struct 를 떠 올 린 다. 구조 에서 필드 만 정 의 된 방법 이 없고 이것 도 deftypedefrecord 가장 기본 적 인 게임 방법 이다.예시
(deftype VNode1 [tag props])
(defrecord VNode2 [tag props])

(def vnode1
  (VNode1. "DIV" {:textContent "Hello world!"}))
;;   (->VNode1 "DIV" {:textContent "Hello world!"})

(def vnode2
  (VNode2. "DIV" {:textContent "Hello world!"}))
;;   (->VNode2 "DIV" {:textContent "Hello world!"})
;;   (map->VNode2 {:tag "DIV", :props {:textContent "Hello world!"}})

  이렇게 보면 둘 다 별 차이 가 없 는 것 같 지만 사실은 멤버 들 의 조작 에 있어 서 차이 가 있다.
;; deftype    
(.-tag vnode1) ;;=> DIV
;; defrecord    
(:tag vnode2)  ;;=> DIV

;; deftype     
(set! (.-tag vnode1) "SPAN")
;;   (aset vnode1 "tag" "SPAN")
(.-tag vnode1) ;;=> SPAN

;; defrecord     ,         
(def vnode3
  (assoc vnode2 :tag "SPAN"))
(:tag vnode2) ;;=> DIV
(:tag vnode3) ;;=> SPAN

  위 에서 우 리 는 defrecord 정 의 된 데이터 구 조 를 맵 으로 볼 수 있 지만 deftype 은 할 수 없다.* 8195. 그러나 상기 한 것 은 모두 기술 이 고 뒤의 길 은 OOP 에서 우 리 는 두 가지 데이터 모델 을 구축 할 것 이다. 1. 프로 그래 밍 분야 모델;2. 응용 분야 모델.프로 그래 밍 분야 모델 (예 를 들 어 String 등) 에 대해 우 리 는 deftype 로 정의 하여 특수 화 능력 을 제공 할 수 있다.그러나 응용 분야 모델 에 있어 우 리 는 이 를 추상 적 으로 하여 기 존의 도구 (예 를 들 어 assoc, filter 등) 로 가공 해 야 한다. 또한 응용 분야 모델 에 있어 모든 속성 은 방문 할 수 있 고 개인 적 인 수요 가 존재 하지 않 아야 한다. 모든 속성 이 변 할 수 없 기 때문이다.
Protocol
프로 토 콜 은 인터페이스 와 같이 인터페이스 프로 그래 밍 을 실시 할 수 있 습 니 다.위 에서 저 희 는 deftypedefrecord 을 통 해 데이터 구 조 를 사용자 정의 할 수 있 습 니 다. 사실은 저 희 는 기 존의 Protocol 이나 사용자 정의 Protocol 을 실현 하여 데이터 구 조 를 확장 하 는 능력 을 가 질 수 있 습 니 다.deftypedefrecord 정의 시 Protocol 실현
;;   protocol IA
(defprotocol IA
  (println [this])
  (log [this msg]))

;;   protocol IB
(defprotocol IB
  (print [this]
         [this msg]))

;;       VNode   IA IB
(defrecord VNode [tag props]
  IA
  (println [this]
    (println (:tag this)))
  (log [this msg]
    (println msg ":" (:tag this)))
  IB
  (print ([this]
    (print (:tag this)))))

;;     
(def vnode (VNode. "DIV" {:textContent "Hello!"}))
(println vnode)
(log vnode "Oh-yeah:")
(print vnode)

주의 IB 에서 print 를 Multi - arity method 로 정의 하기 때문에 하나의 함수 서명 만 실현 하 더 라 도 Multi - arity method 방식 으로 이 루어 져 야 합 니 다.
(print ([this] (print (:tag this))))

그렇지 않 으 면 java.lang.UnsupportedOperationException: nth not supported on this type: Symbol 의 이상 을 보고 할 것 이다.
기 존 데이터 구조 추가 구현 Protocol
  Protocol 의 강력 한 점 은 우리 가 실행 할 때 기 존의 데이터 구 조 를 확장 할 수 있 는 행위 이다. 그 중에서 extend-type 특정한 데이터 구 조 를 통 해 여러 개의 Protocol 을 실현 하고 extend-protocol 여러 개의 데이터 구 조 를 통 해 지정 한 Protocol 을 실현 할 수 있다.1. 사용 extend-type
;;   js/NodeList,      seq
(extend-type js/NodeList
  ISeqable
  (-seq [this]
    (let [l (.-length this)
          v (transient [])]
      (doseq [i (range l)]
        (->> i
          (aget this)
          (conj! v)))
      (persistent! v))))
;;   
(map
  #(.-textContent %)
  (js/document.querySelector "div"))

;;   js/RegExp,           
(extend-type js/RegExp
  IFn
  (-invoke ([this s]
    (re-matches this s))))

;;   
(#"s.*" "some") ;;=> some

2. 사용 extend-protocol
;;   js/RegExp js/String,           
(extend-protocol IFn
  js/RegExp
  (-invoke ([this s] (re-matches this s)))
  js/String
  (-invoke ([this n] (clojure.string/join (take n this)))))

;;   
(#"s.*" "some") ;;=> some
("test" 2) ;;=> "te"

또한 저 희 는 satisfies? 을 통 해 특정한 데이터 형식 인 스 턴 스 가 지정 한 Protocol 을 실현 하 는 지 확인 할 수 있 습 니 다.
(satisfies? IFn #"test") ;;=> true
;;  IFn        Ifn?
(Ifn? #"test") ;;=>true
reify 구조 가 지정 한 Protocol 의 무 속성 인 스 턴 스 를 실현 합 니 다.
(defn user
  [firstname lastname]
  (reify
    IUser
    (full-name [_] (str firstname lastname))))
;;   
(def me (user "john" "Huang"))
(full-name me) ;;=> johnHuang
specifyspecify! 를 사례 로 추가 Protocol 실현specify 가 변 (immutable) 과 복사 가능 (copyable, ICloneable) 의 값 을 추가 로 지정 한 Protocol 을 실현 할 수 있 습 니 다.사실 cljs 값 에 추가 하 는 거 야!
(def a "johnHuang")
(def b (specify a
         IUser
         (full-name [_] "Full Name")))

(full-name a) ;;=>  
(full-name b) ;;=>Full Name
specify! JS 값 추가 지정 프로 토 콜 구현 가능
(def a #js {})
(specify! a
  IUser
  (full-name [_] "Full Name"))

(full-name a) ;;=> "Full Name"

총결산
『 8195 』 cljs 는 데이터 구 조 를 추상 화 하 는 것 을 권장 하기 때문에 List, Map, Set, Vector 외 에 Seq 도 제공 합 니 다.맵, filter, reduce 등 일련의 데이터 조작 함수 가 내장 되 어 있 습 니 다.한편, deftype, defrecord 는 대상 을 대상 으로 프로 그래 밍 을 하거나 내 장 된 조작 이 부족 하여 논 리 를 설명 할 때 확장 하 는 수단 으로 사용 합 니 다.바로 deftype, defrecorddefprotocol 우 리 는 OOP 에서 FP 를 돌 릴 때 더욱 편안 함 을 느 꼈 다.  또한 deftype, defrecord 와 protocol 세트 는 Expression Problem 을 효과적으로 해결 합 니 다. 구체 적 으로 보 세 요.http://www.ibm.com/developerw...
오리지널 을 존중 합 니 다.http://www.cnblogs.com/fsjohn... ^_^뚱보 존

좋은 웹페이지 즐겨찾기