2011-08-24 5 views
11

binding 양식은 클로저에서 리 바인딩 가능 동적 범위 지정을 허용한다는 것을 알고 있습니다. 지금까지 내가 본 적이있는 유일한 용도는 print과 같은 I/O와 같습니다. *out*은 그 당시의 작가에게 리바운드됩니다.클로저에 '바인딩'을 사용하는 좋은 예는 무엇입니까?

다른 설비가 실제로 작동하지 않는 binding의 힘을 실제로 활용하는 예제를보고 싶습니다. 개인적으로 나는 모든 기능에 사용자가 제공 한 객체를 돌아 다니는 것이 정말 지루한 경우에만 사용했습니다. 기본적으로 헬퍼 함수가 사용하는 컨텍스트를 만드는 중입니다. (이 경우 When should one use the temporarily-rebind-a-special-var idiom in Clojure?과 유사합니다.) 더 구체적으로 말하면, 사용자가 *db* var에 대한 동적 바인딩을 작성하여 데이터베이스 기능이 무엇을 조작해야하는지 알 수있게하는 것입니다. 이 기능은 사용자가 데이터베이스 함수에 많은 중첩 호출을 작성해야 할 때 특히 유용합니다. 일반적으로 일을 더 쉽게하기 위해 매크로를 작성해야하지만, 사용자에게 그렇게하도록 요구하는 것은 좋지 않습니다. 즉, 가능한 한 많이하는 것을 피하려고합니다.

복사하여 내 코드에 통합 할 수있는 '바인딩'의 다른 유용한 사용 사례는 무엇입니까?

+0

모두에게 좋은 답변입니다. 다른 사람이 찌르는 경우를 대비하여 대답을 선택하기 전에 며칠 더 남겨 두겠습니다. – bmillare

답변

8

나는 두 가지 이유에 대한 바인딩을 사용 : 데이터베이스 연결이나 메시지 브로커 채널과 같은 "글로벌"자원을 사용

    1. 상수 또는 다른 기호의 다른 값을 대체 테스트를 실행

    테스트

    여러 구성 요소가있는 분산 시스템에서 작업하고 있습니다. 메시지 교환을 통해 메시지를 보내 통신합니다.

    (ns const) 
    (def JOB-EXCHANGE "my.job.xchg") 
    (def CRUNCH-EXCHANGE "my.crunch.xchg") 
    ;; ... more constants 
    

    이 상수가 바로 이곳에 메시지를 보낼 장소의 숫자에 사용되는 이러한 교류는 I는 다음과 같이 정의 한 글로벌 이름을 가지고있다. 코드를 테스트하려면 테스트 스위트의 일부가 실제 메시지 교환을 사용하는 코드를 실행해야합니다. 그러나, 나는 실제 시스템에 간섭하는 테스트를 원하지 않는다.

    이 문제를 해결하기 위해, 나는이 상수 재정의하는 binding 호출에 내 테스트 코드를 래핑이 binding 기능의 내부

    ;; in my testing code: 
    (binding [const/CRUNCH-EXCHANGE (str const/CRUNCH-EXCHANGE (gensym "-TEST-")) 
          const/CRUNCH-TASK-QUEUE (str const/CRUNCH-TASK-QUEUE (gensym "-TEST-"))] 
        ;; tests here 
    ) 
    

    을, 나는 상수를 사용하는 코드를 호출 할 수 있습니다 그리고 그것은을 사용합니다 재정의 된 값. 글로벌 자원

    내가 바인딩을 사용하는 또 다른 방법을 사용하여

    특정 범위 내에서 전역 또는 단일 자원의 값을 "수정"하는 것입니다.여기에 내가 기호 *amqp-connection*에 RabbitMQ Connection의 값을 바인딩 내가 쓴 RabbitMQ 라이브러리의 예입니다 그래서 내 코드를 사용할 수 :

    (with-connection (make-connection opts) 
        ;; code that uses a RabbitMQ connection 
    ) 
    

    with-connection의 구현은 매우 간단합니다 :

    (def ^{:dynamic true} *amqp-connection* nil) 
    
    (defmacro with-connection 
        "Binds connection to a value you can retrieve 
        with (current-connection) within body." 
        [conn & body] 
        `(binding [*amqp-connection* ~conn] 
        [email protected])) 
    

    내 RabbitMQ 라이브러리의 모든 코드는 *amqp-connection*에서 연결을 사용할 수 있으며 유효한 것으로 가정합니다. Connection. 같은 JVM에서 실행되는 여러 repls가있을 수 있습니다

    (defn current-connection 
        "If used within (with-connection conn ...), 
        returns the currently bound connection." 
        [] 
        (if (current-connection?) 
        *amqp-connection* 
        (throw (RuntimeException. 
         "No current connection. Use (with-connection conn ...) to bind a connection.")))) 
    
  • +0

    마지막 코드 블록에서'(if (current-connection?)'표현식이 맞습니까? 아니면 ('amqp-connection *)'이 될 수 있습니까 아니면'current-connection? –

    +1

    Kenny, 'current-connection?'은 var'* amqp-connection * '을'숨기기 '위해서만 존재합니다. (사실입니까? * amqp-connection *)? ('true? * amqp-connection *)'처럼 간단하게 구현할 수 있습니다. 내가 생각하는 코드 스타일의 문제는 var를 직접 사용하는 데 아무런 해가 없습니다. – Gert

    2

    VimClojure 백엔드에서 : 또는 당신이 with-connection에 RabbitMQ 전화를 포장하는 것을 잊었다 설명 예외를 던지는 (current-connection) 기능을 사용합니다. 그러나 Vim과 백엔드 사이의 연결이 연속적이지 않기 때문에 잠재적으로 각 명령에 대해 새 스레드를 얻습니다. 따라서 명령간에 쉽게 상태를 유지할 수 없습니다.

    VimClojure의 기능은 다음과 같습니다. *warn-on-reflection*, *1, *2 등과 같이 흥미로운 바 (var)가 모두 포함 된 binding을 설정합니다. 그런 다음 명령을 실행 한 후 binding의 잠재적으로 변경된 Vars를 일부 관리 인프라에 저장합니다.

    모든 명령에서 "나는 4711에 속합니다"라고 말하면서 그 repl의 상태를 볼 수 있습니다. repl의 상태에 영향을주지 않고 0815.

    2

    바인딩 기능은 테스트 코드에서 도움이 될 수 있습니다. 이는 vars에 함수를 저장하는 큰 장점 중 하나입니다 (기본적으로 Clojure가 수행함).

    내가 작성한 암호화 프로그램의 일부입니다.

    (defmacro with-fake-prng [ & exprs ] 
        "replaces the prng with one that produces consisten results" 
        `(binding [com.cryptovide.split/get-prng (fn [] (cycle [1 2 3]))] 
        [email protected])) 
    

    키 생성기 기능을 어떻게 단위 테스트합니까? 그것은 예측할 수없는 것으로되어 있습니다. 어디서나 (if testing ...)을 쓰거나 조롱 프레임 워크를 사용할 수 있습니다. 또는 난수 생성기를 "동적으로 조롱 (mock)"하는 매크로를 사용할 수 있으며이 을 테스트 코드에만 넣으면 생산 측에 거칠기가 없습니다.

    (deftest test-key-gen 
        (with-fake-prng 
         ....)) 
    
    관련 문제