2012-05-02 35 views
11

Có thể khai báo hàm variadic trong Clojure có thể được gọi là phương thức varargs từ Java không?Cách gọi hàm Clojure variadic từ Java

xem xét trích này từ một số mã đang được phát triển:

(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))) 

Có cách nào tôi có thể đặt ở vị trí của ????? để cho phép Java để gọi phương thức exprFactory và để biết rằng nó là một phương pháp varargs:

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); 

để làm điều này một chút rõ ràng hơn, tôi biết tôi sử dụng Object ở vị trí của ????? và thay đổi exprFactory tới:

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

..nhưng có nghĩa là tôi phải viết Java gọi như thế này:

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 })); 

Một lần nữa, tôi biết tôi có thể viết một phương pháp varargs wrapper trong Java mà các cuộc gọi không variadic exprFactory, nhưng tôi d muốn tránh điều đó nếu có thể.

+0

và Object [] không hoạt động? –

+0

@andrew Đó là điều đầu tiên tôi thử, và tôi cũng đã thử Object ... khớp với cú pháp Java. –

+1

vì varargs chỉ là một cheat bởi trình biên dịch giống như một mảng trong chữ ký kiểu, bạn có thể chỉ định một '' String [] '' với điều này: '' "[Ljava.lang.String;" ' 'thay vì' '?????' '. Tôi đã thử nó, nó biên dịch, nhưng nhật thực sẽ không nhận ra các varargs, nó nhấn mạnh vào một '' String [] '' thậm chí tho một lớp java và một lớp gen-class có sigs loại giống hệt nhau. Bạn có thể có nhiều may mắn hơn – sw1nn

Trả lời

1

tôi sẽ đề nghị bằng văn bản chức năng helper bạn ở phía bên Java, một cái gì đó giống như "applyToHelper" trong clojure.lang.AFn

Điều này sẽ mang hình thức của một hàm Java mà trông giống như sau:

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 
    } 
    } 

Đó là một chút của một hack và phụ thuộc vào định nghĩa nội bộ của clojure.lang.IFn, nhưng ít nhất bạn sẽ nhận được cú pháp variadic tương đối tốt đẹp ở phía Java (tức là không cần phải làm công cụ new Object[] {...}).

+0

Tôi nghĩ rằng có thể là quá mức cần thiết cho những gì tôi đang cố gắng đạt được. Để rõ ràng, ở phía Clojure, tôi muốn cuối cùng gọi là 'expr-factory' với một chuỗi các đối số tùy chọn (các toán hạng cho một biểu thức) - một ref cho chuỗi đó được lưu trữ trong 'Object' được trả về. Biểu mẫu '(apply ...)' trong hàm '-exprFactory' chỉ được sử dụng để mở rộng mảng Java. Có lẽ có một cách hiệu quả hơn để giao diện '-exprFactory' và' expr-factory' như tôi biết các arg hiện đang đi từ mảng Java -> sequence -> phẳng danh sách arg -> sequence. –