2010-09-10 45 views
15

Tôi biết những điều cơ bản về clojure/java interop: gọi java từ clojure và ngược lại. Tuy nhiên, tôi không thể trả lại một bộ sưu tập đã nhập từ clojure sang java. Tôi đang cố gắng để xem một cái gì đó của thiên nhiên đó List<TypedObject> từ mã java được gọi vào clojure.Làm cách nào để chuyển bộ sưu tập đã nhập từ clojure sang java?

Java Object: 

public class TypedObject { 
    private OtherType1 _prop1; 
    public OtherType1 getProp1() { 
     return _prop1; 
    } 
    public void setProp1(OtherType1 prop1) { 
     _prop1 = prop1; 
    } 
} 

CLojure method: 

(defn -createListOfTypedObjects 
     "Creates and returns a list of TypedObjects" 
     [input] 
     ;Do work here to create and return list of TypedObjects 
     [typedObj1, typedObj2, typedObj3]) 

(:gen-class 
:name some.namespace 
:methods [createListofTypedObjects[String] ????]) 

Chúng ta hãy xem xét rằng tôi đang viết một API bằng clojure, được phân phối dưới dạng tệp jar, được sử dụng từ java. Câu hỏi của tôi thực sự là cách để vượt qua vị trí của ???? câu hỏi đánh dấu ở trên bên trong: gen-class cho AOT, để một lập trình viên viết một đoạn mã trong java bằng cách sử dụng api của tôi, có thể có sự hoàn thành intellisense/mã thích hợp (ví dụ: createListofTypedObjects() returns List<TypedObject>) từ trong nhật thực chẳng hạn.

+0

một ví dụ ngắn về mã java gọi clojure thực sự sẽ giúp tôi anser này :) –

+0

Cảm ơn bạn Alex và Stuart cho câu trả lời của bạn. Họ làm cho cảm giác hoàn hảo, nhưng không hoàn toàn những gì tôi đang tìm kiếm. Hy vọng rằng, câu hỏi của tôi bây giờ ít mơ hồ hơn. – user258030

Trả lời

20

Những người khác là đúng mà Clojure không đảm bảo các loại phần tử trong bộ sưu tập trả lại, v.v. (Thực tế, JVM không đảm bảo các loại phần tử trong bộ sưu tập - đó là xử lý hoàn toàn bởi javac.)

Tuy nhiên, tôi có thể thấy giá trị cung cấp API cho các lập trình viên Java khác chỉ định giao diện khai báo các giá trị trả về (hoặc tham số) được tham số theo nhiều cách khác nhau; điều này đặc biệt hấp dẫn nếu người ta đang tìm cách sử dụng Clojure trong môi trường Java hiện có mà không tạo ra sóng.

này hiện đòi hỏi một quá trình hai bước:

  • định nghĩa một giao diện riêng biệt (trong Java!) Mà xác định các loại tham số theo ý muốn
  • xác định gen-class namespace của bạn (hoặc proxy hoặc reify chẳng hạn) như vậy nó triển khai giao diện đó

(Clojure cung cấp biểu mẫu definterface cho phép bạn tránh định nghĩa giao diện Java riêng biệt, nhưng definterface, giống như phần còn lại của Clojure, không cung cấp để chỉ định các loại tham số. Có thể một ngày nào đó ... :-))

ví dụ:

public interface IFoo { 
    List<TypedObject> createListOfTypedObjects(); 
} 

và sau đó bạn namespace gen hạng:

(ns your.ns.FooImpl 
    (:gen-class 
    :implements [IFoo])) 
(defn -createListOfTypedObjects 
    [] 
    [typedObj1, typedObj2, typedObj3]) 

Khi người dùng tạo ra các trường hợp FooImpl, họ sẽ ví dụ hoàn thành mã cho biết phương thức trả về List<TypedObject> thay vì Object hoặc loại không được tham số List.

Nếu bạn đang sử dụng các công cụ xây dựng sane (ví dụ: maven, gradle hoặc kiến ​​được định cấu hình đúng), thì bạn có thể đặt giao diện Java trong dự án Clojure của mình và phụ thuộc vào ngôn ngữ chéo sẽ được xử lý.

+0

V câu trả lời hữu ích. Đó là tầm quan trọng quan trọng để cung cấp các định nghĩa được gõ mạnh mẽ phù hợp để chạy trong java env. Ít khi các loại không xuất hiện sau khi tất cả vì hầu hết các công việc liên quan đến các bộ sưu tập và thường chúng tôi muốn xác định những gì chúng chứa. – javadba

11

Nếu bạn đang cố gắng chuyển một thứ gì đó như List<String> sang phương thức java, thì bạn không cần phải lo lắng về điều đó. Thông số loại (ví dụ: String) chỉ được trình biên dịch javac sử dụng, vì vậy, bất kỳ List nào cũng chỉ hoạt động tốt khi chạy.

Mặt khác nếu bạn đang cố gắng để vượt qua một mảng của một loại đối tượng cụ thể (ví dụ: String[]), sau đó bạn có thể sử dụng khác nhau -array chức năng:

user=> (make-array String 10)   ; an empty String array 
#<String[] [Ljava.lang.String;@78878c4c> 
user=> (into-array ["foo" "bar"])  ; array type inferred from first element 
#<String[] [Ljava.lang.String;@743fbbfc> 
user=> (into-array Number [1.2 5 7N]) ; explicit type array 
#<Number[] [Ljava.lang.Number;@7433b121> 
10

Bạn không cần phải lo lắng về generics (typed collections) trong Clojure. Generics thực sự chỉ là gợi ý kiểu cho trình biên dịch Java. Trong một chương trình Java đang chạy, List<String> có hiệu quả giống như List<Object>.

Vì vậy, ví dụ: một vector Clojure chứa Strings đã là List<String> không cần chuyển đổi.

+1

Không đúng sự thật. Tôi sẽ nói chính xác hơn, bạn _usually_ không cần lo lắng về các bộ sưu tập đã nhập trong Clojure. Vì câu hỏi này là đặc biệt đối phó với Java interop, điều quan trọng là chỉ ra rằng bộ sưu tập có thể tại một thời điểm nào đó được truyền lại cho một phương thức Java. Trong trường hợp này, kiểu của các phần tử trong bộ sưu tập có thể quan trọng nếu tên phương thức bị quá tải lấy các bộ sưu tập với các kiểu phần tử khác nhau. Tôi hiểu điều này có thể mơ hồ và không phổ biến ... nhưng nó tồn tại. – Jason

+0

Tôi không biết cách nào để biểu thị các phép tính tức thời của generics trong Clojure. Ví dụ, người ta có thể viết 'java.lang.ArrayList' nhưng không viết' java.langArrayList '. Nếu bạn nói đúng, @ Jason, liệu sự thiếu này có thể là một lỗ hổng trong Clojure-Java interop không? Có thể có các API trong Java không thể gọi được từ Clojure vì các loại tập hợp biến đổi không thể biểu thị được? Các câu trả lời ở trên và dưới đây cho thấy không, nghĩa là, chúng tôi ổn, ít nhất là bây giờ. –

Các vấn đề liên quan