【问题标题】:taking java method names as function arg in clojure将java方法名称作为clojure中的函数arg
【发布时间】:2010-12-15 17:03:13
【问题描述】:

全部,

我想创建一个函数,它接受一个表示 java 方法的符号并将其应用于某个对象:

(user=> (defn f [m] (. "foo" (m)))

执行此操作时,我得到的结果与我的预期大不相同

user=> (f 'getClass)
java.lang.IllegalArgumentException: No matching method found: m for class java.lang.String (NO_SOURCE_FILE:0)

2 个问题:

1> 为什么符号 m 被称为 '.' 的第二个参数函数而不是绑定到 m 的值?

2> 我将如何做我想做的事?

【问题讨论】:

    标签: function clojure macros


    【解决方案1】:

    它不起作用,因为 .special form 并且具有特殊的评估规则。普通函数调用会计算它们的参数,但. 不会计算方法名参数。

    要使其工作,请使用eval 或将您的函数更改为宏。

    user=> (defmacro foo [o m] `(. ~o ~m))
    #'user/foo
    user=> (foo 123 toString)
    "123"
    user=> (defn bar [o m] (eval `(. ~o ~m)))
    #'user/bar
    user=> (bar 123 'toString)
    "123"
    

    一般不建议使用eval

    【讨论】:

      【解决方案2】:

      问题在于方法调用在 JVM 字节码中是硬连线的。正如 Brian 所说,eval 会起作用,因为它每次调用时都会编译代码。但是请远离eval。它有它的用途,但这不是其中之一。

      最好的方法是使用反射来做你想做的事。或者如果可能的话,使用 Brian 展示的宏。反射可以通过:

      (defn f
        [m & args]
        (clojure.lang.Reflector/invokeInstanceMethod obj m (into-array Object args)))

      虽然没有真正测试过......

      【讨论】:

        【解决方案3】:

        Brian 暗示的宏已经存在,并且被称为memfn,代表“成员函数”。

        user> ((memfn length) "test")
        4
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-09-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-08
          • 1970-01-01
          • 1970-01-01
          • 2014-02-09
          • 1970-01-01
          相关资源
          最近更新 更多