在我的用例中,我有一个带有两个参数的多方法,它们都是映射。第一个用于计算调度值等。第二个是一种上下文变量,它将被实现方法修改或未修改地返回。
(defmulti code (fn [input _] (:cmd input)))
; example implementation
(defmethod code "foo" [_ {var :var :as ctx}]
{:out (str "foo; ctx.var=" var)
:ctx ctx})
如您所见,在此示例实现中,我返回了未修改的上下文变量。由于我有很多不修改上下文的实现,我决定编写一个宏来为我编写 def 方法,将计算输出放在键
:out
下,将未修改的上下文放在 :ctx
下:
(defmacro stable-ctx [multifn dispatch-val args impl]
`(defmethod ~multifn ~dispatch-val ~args
{:out ~impl
:ctx (second ~args)}))
这适用于以下实现:
(stable-ctx code "bar" [_ _] "bar")
(stable-ctx code "foo2" [_ ctx] (str "foo2; ctx.var=" (:var ctx)))
但是,如果我在我的定义中使用析构函数,很明显它会失败:
(stable-ctx code "foo3" [_ {var :var}] (str "foo3; ctx.var=" var))
(
(code {:cmd "foobar"} {:var 2})
的输出是{:out "foobar; ctx.var=2", :ctx {2 :var}}
而不是{:out "foobar; ctx.var=2", :ctx {:var 2}}
)
我想知道如何解决这个问题。我怀疑 clojure.core/destructure 函数可以帮助我解决这个问题,但遗憾的是它缺少文档。
只需为上下文参数使用不同的私有名称,以及
let
客户想要的名称。他们可以用他们的名字做任何他们想做的事,你仍然会有你的名字。
(defmacro stable-ctx [multifn dispatch-val [a b] impl]
`(defmethod ~multifn ~dispatch-val [~a y#]
(let [~b y#]
{:out ~impl
:ctx y#})))
这里
b
和 y#
是同一事物的两个名称,但是 y#
已知是您创建的 gensymmed 符号,因此返回是安全的。 b
是客户放入 arg 向量中的任何内容,因此如果他们愿意,可以对其进行解构。
也许我遗漏了什么,但你总是可以将解构移动到
impl
代码中,例如:
(stable-ctx code "foo3" [args]
(let [{var :var} (second args)]
(str "foo3; ctx.var=" var)))