Clojure将字符串变量作为一个符号求值,这样使用读取字符串可以吗



我可以使用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))

编辑:一个使用读取字符串和评估的版本,它实际上按照我想要的方式工作。

(defn memfn' [fn-name arg-name]
(eval (read-string (str "(memfn " fn-name " " arg-name ")"))))

我是否缺少一个基本的宏构建工具,可以像read-string那样,将符号引用的字符串转换为文本,而不需要执行代码?

谢谢你的任何想法!

无论有没有读取字符串,都无法做到这一点。你提出的解决方案不起作用。您真正想要区分的不是字符串和符号,而是运行时数据和编译时文字。宏不会计算它们接收到的参数,因此即使fn-name是值为"startsWith"的var的名称,memfn(或您的memfn'宏(也只能看到fn-name

如果您只想调用java方法,那么您可以依赖java.lang.reflect.Method及其invoke方法。

这样的方法应该适用于无参数方法,并且不需要宏。

(defn memfn' [m]
(fn [o] (.invoke (.getMethod (-> o .getClass) m nil) o nil)))
((memfn' "length") "clojure")
;=>7

最新更新