bmi*_*are 11 clojure dynamic-binding
我知道该binding表单允许在clojure中重新绑定动态范围.到目前为止,我所见过的唯一用途是用于I/O,例如在print哪里*out*可以反弹到你当时想要的作家.
我希望看到真正利用binding其他设施无法正常工作的优势的例子.就个人而言,我只是在将用户提供的对象传递给所有函数的情况下才使用它真的很乏味.基本上我正在尝试创建辅助函数使用的上下文.(类似于这种情况何时应该在Clojure中使用临时重新绑定-a-special-var成语?)更具体地说,我依靠用户创建动态绑定到*db*var以允许数据库函数知道操作什么.当用户需要编写大量嵌套调用数据库函数时,这特别有用.通常,我很好,如果我需要编写宏来让自己更容易,但要求用户这样做似乎很糟糕.话虽如此,我尽量避免这样做.
"绑定"的其他一些好用例有哪些我可以复制并合并到我的代码中?
我使用绑定有两个原因:
测试
我正在开发一个分布式系统,其中包含几个通过消息交换发送消息进行通信的组件.这些交换有全局名称,我已经定义如下:
(ns const)
(def JOB-EXCHANGE "my.job.xchg")
(def CRUNCH-EXCHANGE "my.crunch.xchg")
;; ... more constants
Run Code Online (Sandbox Code Playgroud)
这些常量用于许多地方以将消息发送到正确的位置.为了测试我的代码,我的测试套件的一部分运行使用实际消息交换的代码.但是,我不希望我的测试干扰实际系统.
为了解决这个问题,我将测试代码包装在一个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
)
Run Code Online (Sandbox Code Playgroud)
在这个binding函数内部,我可以调用任何使用常量的代码,它将使用重写的值.
使用全球资源
我使用绑定的另一种方法是在特定范围内"修复"全局或单例资源的值.这是我编写的RabbitMQ库的示例,其中我将RabbitMQ的值绑定Connection到符号,*amqp-connection*以便我的代码可以使用它:
(with-connection (make-connection opts)
;; code that uses a RabbitMQ connection
)
Run Code Online (Sandbox Code Playgroud)
实施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]
~@body))
Run Code Online (Sandbox Code Playgroud)
我的RabbitMQ库中的任何代码都可以使用该连接,*amqp-connection*并假设它是有效的,开放的Connection.或者使用该(current-connection)函数,当您忘记将RabbitMQ调用包装在with-connection:时,会抛出描述性异常:
(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."))))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1005 次 |
| 最近记录: |