宏中的绑定未解析

a binding in a macro isn't resolved

我正在为 API 服务器创建一个库,这是我拥有的一个简化版本:

(defonce ^:dynamic *my-token* nil)

(defmacro def-my-token
  [token1 & body]
  `(binding [*my-token* ~token1] ~@body))

主要"post"方法:

(defn my-post-request [url1]
  (try
    (let [res (client/post (str "api/url/base" url1)
                {:body (json/write-str (:secret my-token)) ;  my-token should come from the macro
      ;......

下面是我想要使用它的方式:

(defn -main [& args]
  (def-my-token "fdsfdsfdsfds" 

    ; now "my-token" should be created and visible in "my-post-request", shouldn't it?
    (print
     (my-post-request "/some_end_point"))))

但是它说 "Unable to resolve symbol: my-token in this context"

我想知道为什么? def-my-token,作为一个宏,不定义它吗?为什么不?以及如何解决这个问题?

更新: 也没有 (defonce ^:dynamic *token* nil) 它不起作用。为什么不? 为什么宏定义不够?

你绑定了 *my-token*,而不是 my-token。尝试:

{:body (json/write-str (:secret *my-token*))

星号只是动态变量的命名约定,它们仍然是实际变量名称的一部分。

对您更新的回答:

根据 binding 的文档,您只能覆盖 已经存在的 变量。这就是为什么如果不建立与动态变量的根绑定,您的解决方案就无法工作的原因。

旁注:

我建议按照 jmargolisvt 所说的去做,并使用普通的 def 而不是 defonce,因为我从未见过使用 defonce 的任何动态 var 定义。

编辑:

doens't def-my-token, being a macros, define it? why not? And how to fix that?

宏本身不定义任何东西,它们是在大多数 Lisp REPL 的 macro-expansion 步骤中转换源代码的小程序。它可以定义您想要的任何内容,但是您应该编写 def 特殊形式。您使用的是 binding 来处理已经存在的变量。 通过在 REPL and/or 阅读此 Whosebug answer.

的答案,您可能会获得更多见解

如果您需要进一步解释为什么需要 overriding: 将 vars 概念化为堆栈是实用的。您使用 def 建立的根绑定是第一层。你程序中的所有东西都会看到这个值,除非你把 "something" 放在它上面。正如您可以想象的那样,在您的示例中 *my-token* 从您的函数中被视为 nil 会导致问题。

binding求救!

它允许您将任何 "on top" 的根绑定(在您的情况下 nil)thread-locally 放入它的正文中,如下所示: