为什么 "Assert failed: >! used not in (go ...) block"

Why "Assert failed: >! used not in (go ...) block"

我正在尝试在我的 REPL 中弄清楚 core.async 并且完全困惑我对 (go-loop ...) 的使用如何不符合 "go block"为了异步的目的!

我的 go-loop 就像...

(async/go-loop [page (range 3)]
  (if (empty? page)
    (async/close! ch)
    (dorun (map (fn [row]
                  (println row)
                  (async/>! ch row)) page)))
  (recur (range (dec (count page)))))

但是 REPL 很不高兴...

=>
#object[clojure.core.async.impl.channels.ManyToManyChannel
        0x23465937
        "clojure.core.async.impl.channels.ManyToManyChannel@23465937"]
0
Exception in thread "async-dispatch-12" java.lang.AssertionError: Assert failed: >! used not in (go ...) block
nil
...

为什么 (go-loop ...) 的范围不足以进行 (async/>! row) 调用?

我应该在这里使用 go-loop 吗?

不幸的是,

>! 和其他停车调用不能在嵌套在 go 中的函数中使用。

go 将您提供的代码转换为状态机并查找停车呼叫。但是它不会查看嵌套函数的内部。

来自Clojure.Asyncs Github best practice page

Unsupported constructs and other limitations in go blocks

The go macro stops translating at function creation boundaries. This means the following code will fail to compile, or may just throw a runtime error stating that <! was used outside of a go block:

(go (let [my-fn (fn [] (<! c))]
    (my-fn)))

This is one thing to remember since many Clojure constructs create functions inside macros. The following are examples of code that will not work as one would expect:

(go (map <! some-chan))
(go (for [x xs]
      (<! x)))