(case-let) یک مکرو برای مدیریت پیامهایی از فرم {{[:message-tag, arg1, arg2, ...]}} با متغیرهای محلی به عنوان متغیرهای گیرنده است. وقتی در یک block 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 دستی + lets - کار میکند
(let [c (chan)]
(go
(let [msg ( (case (first msg)
:a (let [[x] (rest msg)] (println "First :a" x))
:b (let [[y] (rest msg)] (println "First :b" y))))
(
): 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 ( :a ([x] (println "Third :a" x))
:b ([y] (println "Third :b" y))))
(
خروجی کنسول براوزر
Second :b 123
First :b 123
Third :a 123 <-- نمیبایست باشند!
Third :b 123