带有外部绑定符号的 core.async go 块可以工作,但不能进行宏扩展

Posted

技术标签:

【中文标题】带有外部绑定符号的 core.async go 块可以工作,但不能进行宏扩展【英文标题】:core.async go block with outside bound symbols works but does not macroexpand 【发布时间】:2021-04-25 00:03:30 【问题描述】:

在过去的几周里,我一直在 Clojure 和 Clojurescript 中使用“core.async”,想知道在 go 中使用外部绑定符号是否是个好主意,因为有一个线程池,并且可能其中任何一个都可以使用绑定符号。它可以评估它,但宏扩展不起作用 - 请参阅以下 sn-ps

我想它应该可以正常工作。 x 是不可变的,不会被并发线程更改。对可变数据使用atom 作为x 也应该有效,因为它是atom XD 例如一个对象引用当然不会工作或可能会产生问题!

(let [x 5]
  (clojure.core.async/go
   (println x)))

;; => 5
;; nil
(clojure.walk/macroexpand-all
   '(let [x 5]
      (clojure.core.async/go
        (println x))))

;; => Syntax error macroexpanding clojure.core.async/go at (your_project.cljc:93:3).
;;    Could not resolve var: x

这似乎可行,但这是一个坏主意吗?为什么?

谁能解释为什么宏扩展不起作用?

【问题讨论】:

【参考方案1】:

macroexpand-all 不是高保真扩展器。它使用适用于简单宏的基本过程,但它并不能完成实际编译器所做的一切。值得注意的是,它没有管理绑定应该引入的&env 映射。我假设 core.async 需要查看 &env 以确定绑定是本地的还是 var。

所以,你不应该指望macroexpand-all 在这里工作,但编写这种代码并没有错。

【讨论】:

感谢您的回复,您知道编译器扩展和宏扩展的区别的文章吗? 我认为没有人写过那篇文章。了解差异的方法是 (1) 充分了解实际编译器宏扩展的方式,以及 (2) 将其与 macroexpand-all 的源代码进行比较,后者的作用非常简单。 那么你从哪里得到源代码或一些关于编译器或其他东西的文档的信息? 在 github 上很容易找到编译器源代码。阅读它当然不是微不足道的,但没有任何知识是免费的。 TBH 我自己对它的了解有些过时了——自从他们添加了 clojure.spec 后我就没有真正跟上,而且显然带有规范的宏已经改变了编译器步骤。

以上是关于带有外部绑定符号的 core.async go 块可以工作,但不能进行宏扩展的主要内容,如果未能解决你的问题,请参考以下文章

带有外部“C”的 C++ 导致重复符号错误

Go 匿名函数与闭包的使用

IDEA使用Maven工具打包带有外部jar包时出错 - 提示程序包不存在和找不到符号

Go语言-make陷阱和闭包函数

Golang中的匿名函数(闭包)

wpf本地和外部绑定