我可以使用memfn创建一个调用Java函数的clojure函数。
(macroexpand '(memfn startsWith prefix))
=> (fn* ([target2780 prefix] (. target2780 (startsWith prefix))))
((memfn startsWith prefix) "abc" "a")
=> true
memfn
要求函数名称是符号。我想知道是否可以编写一个宏来调用名称作为字符串提供的任意方法。也就是说,我希望能够调用以下内容:
(def fn-name "startsWith")
=> #'user/fn-name
(macroexpand '(memfn' fn-name "prefix"))
=> (fn* ([target2780 prefix] (. target2780 (startsWith prefix))))
((memfn fn-name "prefix") "abc" "a")
=> true
我唯一想到的方法就是使用read-string
。
(defmacro memfn' [fn-name arg-name]
`(memfn ~(read-string fn-name) ~arg-name))
编辑:使用读取字符串和eval的版本实际上可以按照我想要的方式工作。
(defn memfn' [fn-name arg-name]
(eval (read-string (str "(memfn " fn-name " " arg-name ")"))))
我是否缺少一种基本的宏构建工具,无法像read-string
那样使用符号引用的字符串并将其转换为文字而无需潜在地执行代码?
感谢任何想法!
答案 0 :(得分:0)
无论有没有读取字符串,都无法做到这一点。您提出的解决方案不起作用。您真正要做出的区分不是字符串和符号之间的区别,而是运行时数据和编译时文字之间的区别。宏不会评估接收到的参数,因此即使fn-name
是值为"startsWith"
的var的名称,memfn
(或您的memfn'
宏)也只会参见fn-name
。
答案 1 :(得分:0)
如果仅对 调用Java方法感兴趣,则可以依赖java.lang.reflect.Method及其调用方法。
类似的事情应该适用于无参数方法,并且不需要宏。
(defn memfn' [m]
(fn [o] (.invoke (.getMethod (-> o .getClass) m nil) o nil)))
((memfn' "length") "clojure")
;=>7