将对象从java传递到Clojure eval

问题描述:

我从Java调用Clojure,并在传入的字符串上调用eval。Java代码将保存对象,并且客户端代码可以指定要在对象上运行的Clojure代码字符串。我知道如何从Java调用Clojure代码,但是如何传递变量?将对象从java传递到Clojure eval

这是我的。首先,一个简单的工作对象:

public class Helloer { 
    public String getGreeting() { return "Hello"; } 
} 

然后一些样板代码调用Clojure方法。

public static String call(Helloer helloer, String expression) throws Exception { 
    RT.loadResourceScript("EvalObject.clj"); 
    final Var schrodEval = RT.var("eval-object", "eval-string"); 
    final String result = (String) schrodEval.invoke(expression, helloer); 
    return result; 
} 

但是后来我被困在Clojure代码中。该对象正常传递,但是如何将该值传递给eval

这是我已经试过:

(ns eval-object) 

(defn eval-string [string this] 
    (eval (read-string string))) 

(defn eval-string2 [string value] 
    (def this) 
    (binding [this value] 
    (eval (read-string string)))) 

(defn eval-string3 [string value] 
    (def this) 
    (eval (list 'binding (vector 'this 5) (read-string string)))) 

这些给:

java.lang.Exception: Unable to resolve symbol: this in this context (NO_SOURCE_FILE:0) 

于是我试图构建一个定义this具有约束力的条款:

(defn eval-string4 [string value] 
    (def this) 
    (eval (list 'do (list 'defonce 'this nil) 
     (list 'binding (vector 'this value) (read-string string))))) 

但现在我得到:

java.lang.RuntimeException: Can't embed object in code, maybe print-dup not defined: [email protected] (NO_SOURCE_FILE:0) 

我错过了什么吗?是否有可能将对象从Java,Clojure传递到eval?

原来错误信息是正确的。我需要定义print-dup。我实现了Helloer类简单的ID查找,并定义为print-dup

(defmethod print-dup com.ziroby.Helloer [h stream] 
    (.write stream "#=(com.ziroby.Helloer/getById ") 
    (.write stream (str (.getId h))) 
    (.write stream ")")) 

显然,Clojure中需要一些方法来打印的目的是能够把它变成一个eval语句。这个print-dup创建一个Clojure语句来通过Helloer.getById(它只是在一个散列表中查找对象)查找对象来“创建”对象。

正如@mikera所说,如果您接受来自调用者的任意代码或动态生成代码,则只需跳过这些环节即可。

这并不完全清楚你的意思是“传递对象到评估”。也许你可以澄清目标多一点?

然而,它可能是你正在寻找的东西是这样的:

(defn call-eval [helloer] 
    (eval `(.getGreeting ~helloer))) 

(call-eval some-helloer) 
=> "Hello" 

几件事情需要注意:

  • 当你做一个eval,您需要报价形式
  • 要通过“对象”,您需要取消引用~)在此表单中,以便该对象被使用dir而不仅仅是一个符号
  • 不需要eval因为(.getGreeting helloer)的工作原理也一样(因为它不需要编译表单,所以效率更高。通常情况下,只有在运行时动态生成新代码或者要读入并接受任意代码作为输入(例如REPL本身)时才需要eval。
+0

我正在做eval的第二个例子。我想阅读并接受任意代码。我希望这个任意代码能够以'this'的形式访问'helloer'对象。 –