Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用';装订';在clojure?_Clojure_Dynamic Binding - Fatal编程技术网

使用';装订';在clojure?

使用';装订';在clojure?,clojure,dynamic-binding,Clojure,Dynamic Binding,我知道,绑定表单允许clojure中可重新绑定的动态范围。到目前为止,我看到它唯一的用途是用于I/O,例如使用print,其中*out*可以恢复到您当时想要的任何编写器 我想看到一些例子,它们真正利用了绑定的强大功能,而其他功能实际上不起作用。就我个人而言,我只在将用户提供的对象传递给所有函数非常繁琐的情况下使用过它。基本上是一种情况,我试图创建一个助手函数使用的上下文。(与本例类似)更具体地说,我依赖于用户创建一个到*db*var的动态绑定,以允许数据库函数知道操作什么。当用户需要编写大量对数

我知道,
绑定
表单允许clojure中可重新绑定的动态范围。到目前为止,我看到它唯一的用途是用于I/O,例如使用
print
,其中
*out*
可以恢复到您当时想要的任何编写器

我想看到一些例子,它们真正利用了
绑定的强大功能,而其他功能实际上不起作用。就我个人而言,我只在将用户提供的对象传递给所有函数非常繁琐的情况下使用过它。基本上是一种情况,我试图创建一个助手函数使用的上下文。(与本例类似)更具体地说,我依赖于用户创建一个到
*db*
var的动态绑定,以允许数据库函数知道操作什么。当用户需要编写大量对数据库函数的嵌套调用时,这尤其有用。通常,如果我需要编写宏来简化自己的工作,我可以,但要求用户这样做似乎不好。尽管如此,我还是尽量避免这样做


“绑定”还有哪些好的用例可以复制并合并到代码中?

我使用绑定有两个原因:

  • 运行覆盖其他符号的常量或其他值的测试
  • 使用“全局”资源,如数据库连接或MessageBroker通道
  • 测试

    我正在开发一个分布式系统,它有几个组件,通过消息交换发送消息进行通信。这些交易所有全球名称,我这样定义:

    (ns const)
    (def JOB-EXCHANGE    "my.job.xchg")
    (def CRUNCH-EXCHANGE "my.crunch.xchg")
    ;; ... more constants
    
    这些常量在许多地方用于将消息发送到正确的地方。为了测试我的代码,我的测试套件的一部分运行使用实际消息交换的代码。但是,我不希望我的测试干扰实际系统

    为了解决这个问题,我将测试代码包装在一个
    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
    )
    
    在这个
    绑定
    函数中,我可以调用任何使用常量的代码,它将使用重写的值

    使用全球资源

    我使用绑定的另一种方法是“修复”特定范围内全局或单例资源的值。下面是我编写的RabbitMQ库的一个示例,其中我将RabbitMQ
    连接的值绑定到符号
    *amqp Connection*
    ,以便我的代码可以使用它:

    (with-connection (make-connection opts)
      ;; code that uses a RabbitMQ 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))
    
    我的RabbitMQ库中的任何代码都可以使用
    *amqp connection*
    中的连接,并假定它是有效的、开放的
    连接。或者使用
    (当前连接)
    函数,当您忘记将RabbitMQ调用包装到带有连接的
    中时,该函数会引发一个描述性异常:

    (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."))))
    

    在VimClojure后端中,可能有多个repl在同一JVM中运行。但是,由于Vim和后端之间的连接不是连续的,因此每个命令都可能有一个新线程。因此,您无法轻松地保留命令之间的状态

    VimClojure所做的工作如下。它使用所有感兴趣的变量设置
    绑定
    ,如
    *反射警告*
    *1
    *2
    ,等等。然后执行该命令,然后将可能更改的变量从
    绑定中存储到某些簿记基础结构中


    所以每个命令都会说“我属于repl 4711”,它会看到repl的状态。不影响repl 0815的状态。

    绑定函数在测试代码中非常有用。这是在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]))]
         ~@exprs))
    
    如何对密钥生成器功能进行单元测试?这应该是不可预测的。您可以在任何地方线程
    (如果测试…
    ),或者使用某种模拟框架。或者,您可以使用一个宏“动态模拟”随机数生成器,并将其仅放在测试代码中,从而使您的生产端不受影响

    (deftest test-key-gen 
       (with-fake-prng 
             ....))
    

    到目前为止,所有的答案都很好。在选择答案之前,我可能会将其保留几天,以防其他人想尝试。最后一个代码块中的
    (if(current connection?
    表达式是否正确?它(或应该)是
    if(*amqp connection*)
    还是
    当前连接?
    基本上是
    (true?*amqp连接*)
    (某些?*amqp连接*)
    ?Kenny,
    当前连接?
    仅存在于从视图中“隐藏”var
    *amqp连接*
    。其实现可以像
    一样简单(true?*amqp连接*)
    就像你说的。我想这是代码风格的问题,直接使用var没有坏处。