2010-04-27 22 views
15

Ví dụ lớp Java này:phương pháp Làm thế nào để gọi quá tải Java trong Clojure

package foo; 
public class TestInterop 
{ public String test(int i) 
    { return "Test(int)"; } 

    public String test(Object i) 
    { return "Test(Object)"; } 
} 

Khi tôi bắt đầu Clojure và cố gắng gọi phương thức thử nghiệm (int), các phương pháp thử nghiệm (Object) được gọi thay vào đó, bởi vì Clojure tự động đóng số nguyên vào một đối tượng java.lang.Integer.

Làm cách nào để buộc Clojure gọi phương thức thử nghiệm (int)?

user=> (.test (new foo.TestInterop) 10) 
"Test(Object)" 

Tôi muốn gọi các phương thức như Component.add(Component comp, int index) trong AWT, nhưng thay vì tiếp tục gọi add(Component comp, Object constraints), vì vậy các nút trên thanh công cụ của tôi luôn xuất hiện theo thứ tự sai.

Trả lời

14

Cuộc thảo luận đang diễn ra trong kênh #clojure trên Freenode ngay bây giờ về chủ đề này. Chris Houser (người sẽ đăng một câu trả lời, nhưng cuối cùng đã quyết định anh ta quá bận rộn để làm điều đó) đã đăng a Gist thể hiện điều gì xảy ra với phương thức quá tải booleanObject; nó chỉ ra rằng trong một số tình huống, ngoài một diễn viên (boolean ...), một gợi ý kiểu là bắt buộc. Cuộc thảo luận khá sáng sủa, với một vài góc tối của quá trình biên dịch Clojure trở nên sáng đẹp. (Xem liên kết tới nhật ký IRC bên dưới.)

Về cơ bản, nếu một đối tượng được tạo ngay trong biểu mẫu gọi phương thức - (.foo (Foo.) ...), nói - gợi ý loại đó là không cần thiết; nó cũng không cần thiết nếu đối tượng đã được xây dựng như một giá trị cho một địa phương ở dạng let kèm theo (xem cập nhật 2 bên dưới và phiên bản Gist của tôi). Nếu đối tượng thu được bằng cách tra cứu Var, mặc dù, một gợi ý kiểu là bắt buộc - có thể được cung cấp hoặc trên chính Var hoặc tại trang cuộc gọi, trên biểu tượng được sử dụng để chỉ Var.

đang

Java từ Gist:

Và mã Clojure:

(.foo (mypkg.Ugly.) 5) 
;=> "obj: 5" 

(.foo (mypkg.Ugly.) true) 
;=> "obj: true" 

(.foo (mypkg.Ugly.) (boolean true)) 
;=> "bool: true" 


(def u (mypkg.Ugly.)) 
(.foo u (boolean true)) 
;=> "obj: true" 

(.foo #^mypkg.Ugly u (boolean true)) 
;=> "bool: true" 

Lưu ý cách trình biên dịch Clojure cần một loại gợi ý trên u để có thể biên dịch một phương pháp gọi trực tiếp . Nếu không, mã dựa trên phản chiếu dường như được tạo ra, điều này dường như mất đi sự theo dõi thực tế rằng đối số có nghĩa là một nguyên thủy trên đường đi.

Các bổ sung của tôi tuân theo (và đây là my fork of the above Gist).

;; renamed mypkg.Ugly to foo.TestInterop2 when doing my tests 
user> (let [t (foo.TestInterop2.)] 
     (.foo t (boolean true))) 
"bool: true" 

;;; type-hinting the Var 
user> (def #^foo.TestInterop2 x (foo.TestInterop2.)) 
#'user/x 
user> (.foo x (boolean true)) 
"bool: true" 

Chủ đề lần đầu tiên được đưa ra at this point. Chouser đăng Gist half an hour later, với các cuộc thảo luận ngày càng trở nên thú vị hơn sau đó.

+0

Điều đó giải thích tại sao nó luôn hoạt động trong các chương trình thử nghiệm chứ không phải trong chương trình thực. Tôi đưa vào gợi ý loại trên cuộc gọi, và nó bây giờ làm việc tốt. Cảm ơn rất nhiều. Tôi đã có một shot để thực hiện một macro cho điều này, vì bạn có thể lấy lớp từ biến, nhưng có vẻ như các gợi ý kiểu không macro-ise. –

+0

Rất vui khi biết điều đó! Oh, và thực sự nó có thể xử lý các gợi ý kiểu trong các macro - và đôi khi một macro được thiết kế tốt có thể tạo ra mã được gợi ý độc đáo với cách gõ tối thiểu. Bạn có thể đăng câu hỏi riêng về điều đó nếu bạn muốn được trợ giúp bằng cách viết một câu hỏi. –

+0

Tôi không thể làm điều này để làm việc với mã của tôi, mặc dù tình hình của tôi hơi khác một chút. Các phương thức java mà tôi đang cố gọi là 'Application.launch' của JavaFX. Tôi muốn phương thức 'launch' tĩnh với đối số' Class 'và dường như không cung cấp gợi ý kiểu cho lời gọi của tôi (tôi đã thử nhiều cách tiếp cận) khiến phương thức' launch' được gọi chính xác và tôi nhận được lỗi "Class không thể được cast thành String". – Jason

8
user=> (.test (foo.TestInterop.) 10) 
"Test(Object)" 
user=> (.test (foo.TestInterop.) (int 10)) 
"Test(int)" 

Số trong Clojure thường được đóng hộp (int => Integer) trừ khi bạn yêu cầu cụ thể về nguyên thủy.

Here là thông tin thêm về nguyên thủy trong Clojure.

+0

Tuyệt vời. Cảm ơn rất nhiều. –

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