2011-04-28 103 views
6

我有一个将实现作为侦听器的Java接口的宏。我定义了宏以获取包含我想要解构的函数的映射,并用于每个接口方法。这是宏: -将函数映射传递给宏

(defmacro with-cache-listener-m [component event body] 
    (let [{:keys [f-insert f-update]} body] 
    `(. ~component addMapListener 
    (proxy [AbstractMapListener] [] 
     (entryInserted [~event] ~f-insert ~event) 
     (entryUpdated [~event] ~f-update ~event))))) 

的身体图是这样的: -

(def m-callbacks {:f-insert callback-insert :f-update callback-update}) 

但是当我打电话(macroexpand '(with-cache-listener-m test-cache e m-callbacks))它扩展为(. test-cache user/addMapListener (clojure.core/proxy [com.tangosol.util.AbstractMapListener] [] (user/entryInserted [e] nil e) (user/entryUpdated [e] nil e)))

的回调函数是零。我是否需要对它们进行不同的定义,或者我是否以这种错误的方式去做。

+0

什么是回调插入和回调更新?当你调用m-callback时,它会产生什么? – rplevy 2011-04-28 14:25:13

+0

他们只是打印他们的论点和返回的两个函数。 M-回调是 用户> M-回调 {:F-插入#<用户$ callback_insert用户$ callback_insert @ 1db87736>:F-更新#<用户$ callback_update用户$ callback_update @ 2d3584f9>} – JPT 2011-04-28 14:50:31

+0

如果你绑定m-callback函数的计算结果是该地图,而不是直接映射到地图上? – rplevy 2011-04-28 15:12:10

回答

4

当您调用with-cache-listener-m宏时,body参数作为符号被限制为'm-callbacks,因此当您尝试解构该局部变量时,它将不起作用,因为它不是一个映射。你可以让生成的表单做这样的工作:

(defmacro with-cache-listener-m [component event body] 
    `(let [{:keys [f-insert# f-update#]} ~body] 
    (. ~component addMapListener 
     (proxy [AbstractMapListener] [] 
      (entryInserted [~event] f-insert# ~event) 
      (entryUpdated [~event] f-update# ~event))))) 

但最终我不知道你的代码需要一个宏,你试图把它写成一个函数:

(defn add-map-listener [component insert-fn update-fn] 
    (.addMapListener component 
    (proxy [AbstractMapListener] [] 
     (entryInserted [e] (insert-fn e)) 
     (entryUpdated [e] (update-fn e))))) 

正如你所看到的,我改变了一些事情:

  • 作出的函数名称更清晰,宏是不是真的像其他与 - *宏,通常在某种特殊评估一些代码(body)上下文。
  • 删除了事件参数,因为它似乎没有任何用处。
  • 使insert-fn和update-fn参数显式化以简化示例。
  • 使用新的方法调用语法。
  • 修复了代理实际使用给定函数的方法。

    ,我已经添加了代码
    (defn add-map-listener [component & functions] 
        (let [{:keys [insert-fn update-fn]} (into {} functions)] 
        (when-not (empty? functions) 
         (.addMapListener component 
         (proxy [AbstractMapListener] [] 
          (entryInserted [e] (insert-fn e)) 
          (entryUpdated [e] (update-fn e))))))) 
    

    通知不调用addMapListener时:

如果你想的功能完全是可选的,并使其能够以任意顺序你总是可以做到这一点给予没有给出任何功能。

+0

这当然清晰得多, 谢谢。但是,我仍然遇到同样的错误,就像我最初将其定义为函数一样。我的函数映射是(def m-callbacks {:insert-fn callback-insert:update-fn callback-update}),但是当我调用add-map-listener时,我得到一个异常,没有为key提供值。 m-callbacks转发给用户> m-callbacks {:insert-fn#,::update-fn#} – JPT 2011-04-28 18:21:46

+0

首先,您会需要像这样使用'apply'(应用add-map-listener m-callbacks)',其次我犯了一个小错误,函数参数需要被转换回地图,现在已经修复了。 – 2011-04-28 18:43:54

+0

您也可以使用args矢量定义'add-map-listener':'[component functions]',以便它直接将地图作为参数。按照我定义的方式,你可以这样调用它:'(add-map-listener test-cache:f-insert callback-insert:f-update callback-update)' – 2011-04-28 18:47:42

1

宏不是函数:它们只知道在编译时传递给它们的文字形式。如果您为变量x分配一个值(例如10),然后将x传递给您的宏,它看起来不是10,而是看到x。如果您的宏不是def ing m-callbacks,然后传递该符号,则只需将该地图直接作为文字传递即可。

+0

我想我真正想知道的是如何定义多个方法的任何Java侦听器接口,都可以通过惯用的方式在宏中实现。我试过这个: - user>(macroexpand'(with-cache-listener -m test-cache e'{:f-insert callback-insert:f-update callback-update})) (。test- cache user/addMapListener(clojure.core/proxy [com.tangosol.util.AbstractMapListener] [](user/entryInserted [e] nil e)(user/entryUpdated [e] nil e))) – JPT 2011-04-28 14:54:48