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!)

; 带有手动 case 和 lets 的 go 块 - 工作
(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]))

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

; go 之内的 case-let - 故障
(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 投票
0 投票
_评论由:tslocke_

我找到了这个问题的简单解决方案。在宏展开过程中,核心名称如{{case}}变为完全限定,即{{cljs.core/case}},并且看起来go宏未能识别case。将{{case}}替换为{{~'case}}在{{let-case}}定义中可以解决问题。

希望这能帮助了解核心.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 报告)
...