请在2024年的Clojure调查问卷分享您的想法!

欢迎!请参阅关于页面以获取更多有关此功能的信息。

0
core.async
(case-let) 是一个处理类似 {{[:message-tag, arg1, arg2, ...]}} 形式消息的宏,并将参数绑定到局部变量。当它用于 go 块中时无法正确工作。请注意,一个简单的带有 case 的宏,例如 (defmacro my-case [expr & cases] `(case ~expr ~@cases)) 是可以工作的。

(附件:示例项目)

(case-let) 定义


(ns core-async-bug.macros)

(defmacro case-let [expr & cases]
  (let [msg (gensym)]
    `(let [~msg ~expr]
       (case (first ~msg)
        ~@(apply concat (for [[key [args & body]] (partition 2 cases)]
                    [key `(let [~args (rest ~msg)] ~@body)]))))))


ClojureScript测试代码


(ns core-async-bug.core
  (:require-macros [cljs.core.async.macros :refer [go]]
                   [core-async-bug.macros :refer [case-let]])
  (:require [cljs.core.async :refer[< put! chan]])

(enable-console-print!)

; go块中带有手动case + 令牌 - 工作
(let [c (chan)]
  (go
    (let [msg (< c)]
      (case (first msg)
        :a (let [[x] (rest msg)] (println "First :a" x))
        :b (let [[y] (rest msg)] (println "First :b" y)))))
  (put! c [:b 123]))

; case-let在go之外 - 工作
(case-let [:b 123]
  :a ([x] (println "Second :a" x))
  :b ([y] (println "Second :b" y)))

; case-let在go内部 - 损坏
(let [c (chan)]
  (go
    (case-let (< c)
      :a ([x] (println "Third :a" x))
      :b ([y] (println "Third :b" y))))
  (put! c [:b 123]))


浏览器控制台输出


Second :b 123
First :b 123
Third :a 123          <-- 不应该在这里!
Third :b 123

3 答案

0

评论由:tslocke 发布

更多讨论在此: https://groups.google.com/forum/#!topic/clojurescript/w21nNWkKR-c

0
_评论由:tslocke 发布_

我发现了一个简单的解决方案来解决这个问题。在宏展开过程中,像 {{case}} 这样的核心名称变为全称,即 {{cljs.core/case}},似乎 go 宏无法正确识别 case。在 {{let-case}} 的定义中将 {{case}} 替换为 {{~'case}} 可以解决这个问题。

我希望这对了解 core.async 代码库的人来说是一个简单的修复方案。

工作的宏是


(defmacro case-let [expr & cases]
  (let [msg (gensym)]
    `(let [~msg ~expr]
       (~'case (first ~msg)
        ~@(apply concat (for [[key [args & body]] (partition 2 cases)]
                    [key `(let [~args (rest ~msg)] ~@body)]))))))
0
参考: https://clojure.atlassian.net/browse/ASYNC-79(由 alex+import 报告)
...