2012-05-02 12 views
11

Ist es möglich, eine Variadic-Funktion in Clojure zu deklarieren, die als Varargs-Methode aus Java aufgerufen werden kann?So rufen Sie eine Clojure Variadic-Funktion von Java

Betrachten Sie diesen Auszug aus einigen Code in der Entwicklung:

(ns com.mydomain.expression.base 
    (:gen-class 
    :name com.mydomain.expression.Base 
    :methods [^:static [exprFactory [String String ?????] Object]] 
) 

(defn expr-factory 
    ; worker function that is also called from Clojure 
    [id func & args] 
    (let [ex ("construction code here")] 
    ex)) 

(defn -exprFactory 
    ; interface method called from Java 
    [idStr funcStr & argsArray] 
    (apply expr-factory idStr funcStr (seq argsArray))) 

Gibt es etwas, was ich anstelle von ????? setzen können Java zu ermöglichen, die exprFactory Methode aufzurufen und zu wissen, dass es ein varargs Methode ist:

import com.mydomain.expression.Base; 
... 
Object e1 = Base.exprFactory("e1", "day"); 
Object e2 = Base.exprFactory("e2", "length", "string"); 
Object e3 = Base.exprFactory("e3", "*", 4, 5); 
Object sum = Base.exprFactory("sum", "+", e1, e2, e3); 

um dies ein wenig klarer zu machen, ich weiß, ich Object anstelle von ????? verwenden und exprFactory ändern:

(defn -exprFactory 
    ; interface method called from Java 
    [idStr funcStr argsArray] 
    (apply expr-factory idStr funcStr (seq argsArray))) 

..aber das bedeutet, dass ich schreiben Java wie folgt aufrufen:

import com.mydomain.expression.Base; 
... 
Object e1 = Base.exprFactory("e1", "day", new Object[0])); 
Object e2 = Base.exprFactory("e2", "length", new Object[] { "string" })); 
Object e3 = Base.exprFactory("e3", "*", new Integer[] { 4, 5 })); 
Object sum = Base.exprFactory("sum", "+", new Object[] { e1, e2, e3 })); 

Noch einmal, ich weiß, ich könnte einen varargs Wrappermethode in Java schreiben, die die Nicht-variadische exprFactory nennen, aber ich Das möchte ich möglichst vermeiden.

+0

und Objekt [] funktioniert nicht? –

+0

@andrew Das war das erste, was ich ausprobiert habe, und ich habe auch Object ausprobiert, was der Java-Syntax entsprechen würde. –

+1

Da varargs nur ein Cheat des Compilers sind, der einfach wie ein Array in der Typ-Signatur aussieht, sollten Sie in der Lage sein, eine '' String [] '' damit anzugeben: '' "[Ljava.lang.String;" ' 'anstelle von' '?????' '. Ich habe das probiert, es kompiliert, aber Eclipse wird die Varargs nicht erkennen, es besteht auf einer '' String [] '' sogar wenn eine Java-Klasse und eine Gen-Class-Klasse identische Typ-Sigs haben. Vielleicht haben Sie mehr Glück – sw1nn

Antwort

1

würde ich vorschlagen, Ihre Hilfsfunktion auf der Java-Seite, so etwas wie der „applyToHelper“ in clojure.lang.AFn

Diese in Form einer Java-Funktion würde schreiben, wie etwas aussieht:

public Object invokeVariadic(IFn function, Object... args) { 
    switch (args.length) { 
     case 0: 
     return function.invoke(); 
     case 1: 
     return function.invoke(args[0]); 
     /// 20-odd more cases 
    } 
    } 

Es ist ein bisschen wie ein Hack und hängt von der internen Definition von clojure.lang.IFn ab, aber zumindest wirst du relativ nette Variadic-Syntax auf der Java-Seite bekommen (dh keine Notwendigkeit, die new Object[] {...} Sachen zu tun).

+0

Ich denke, das könnte für das, was ich erreichen möchte, zuviel sein. Zur Klarstellung möchte ich auf der Clojure-Seite schließlich 'expr-factory' mit einer optionalen Sequenz von Argumenten (Operanden für einen Ausdruck) aufrufen - ein Verweis auf diese Sequenz wird in dem zurückgegebenen 'Objekt' gespeichert. Das '(apply ...)' -Formular in der '-exprFactory'-Funktion wird nur zum Erweitern des Java-Arrays verwendet. Vielleicht gibt es einen effizienteren Weg, '-exprFactory' und' expr-factory' zu verbinden, da mir bewusst ist, dass die Argumente derzeit aus Java-Array -> Sequenz -> abgeflachte Arg-Liste -> Sequenz stammen. –