Clojure 将字符串变量作为符号进行评估,这样使用读取字符串可以吗?

Clojure evaluating string variable as a symbol, is this use of read-string okay?

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

编辑:使用 read-string 和 eval 的版本实际上按照我想要的方式工作。

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

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

感谢任何想法!

无论有无读取字符串,都无法做到这一点。您提出的解决方案不起作用。您真正想要区分的不是字符串和符号之间的区别,而是运行时数据和编译时文字之间的区别。宏不会评估它们收到的参数,因此即使 fn-name 是一个值为 "startsWith" 的变量的名称,memfn(或您的 memfn' 宏)也只会永远参见 fn-name

如果您有兴趣调用 java 方法 那么您可以依赖 java.lang.reflect.Method 及其调用方法。

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

(defn memfn' [m]
  (fn [o] (.invoke (.getMethod (-> o .getClass) m nil) o nil)))

((memfn' "length") "clojure")
;=>7