2011-07-08 10 views
6

Jestem nowicjuszem w clojure i Java.Dostęp do pól Java dynamicznie w Clojure?

W celu uzyskania dostępu do pola Java w Clojure można zrobić:

Classname/staticField 

który jest tak samo jak

(. Classname staticField) 

(poprawcie mnie jeśli się mylę)

Jak mogę uzyskać dostęp do pola statycznego, gdy nazwa pola jest przechowywana w zmiennej? tj .:

(let [key-stroke 'VK_L 
     key-event KeyEvent/key-stroke]) 

Chcę key-stroke być oceniane pod symbolem VK_L przed próbuje uzyskać dostęp do pola.

+3

Oprócz odpowiedzi skuro, można patrzeć na odbicie Java API. Zobacz sekcję "Zmiana wartości pól" na stronie http://java.sun.com/developer/technicalArticles/ALT/Reflection/. – gatoatigrado

+0

Aby wyjaśnić nieco więcej: Dostęp do pól lub wywołań metod musi być skompilowany w kodzie bajtowym. Dlatego nie można ich skonstruować za pomocą informacji o środowisku wykonawczym. Jeśli tego potrzebujesz, będziesz musiał użyć refleksji. (patrz odpowiedź Joosta) – kotarak

Odpowiedz

9

W tym przypadku może chcesz zrobić coś jak następuje:

user=> (def m 'parseInt)   
#'user/m 
user=> `(. Integer ~m "10")  
(. java.lang.Integer parseInt "10") 
user=> (eval `(. Integer ~m "10")) 
10 

Jeśli czujesz, że to trochę hack-owski, to dlatego, że to naprawdę jest takie. Mogą istnieć lepsze sposoby struktury kodu, ale przynajmniej to powinno działać.

+0

Czy ta odpowiedź ci pomogła? Chcesz go zaakceptować (czy kogokolwiek innego)? – skuro

4

Reflection jest chyba właściwa droga do podjęcia, ale najłatwiej jest

(eval (read-string (str "KeyEvent/" key-stroke))) 

To będzie po prostu przekształcić wygenerowany ciąg do ważnego Clojure, a następnie ocenić go.

1

Można skonstruować właściwą rozmowę jako s-expression i ocenić go w następujący sposób:

(let [key-stroke 'VK_L 
     key-event (eval `(. KeyEvent ~key-stroke))] 
    ....do things with your key-event......) 

Jednakże, jeśli to, co staramy się robić to badanie, czy dany klawisz został naciśnięty, może nie trzeba żadnych z tego: ja zazwyczaj uważają, że najłatwiej jest napisać kod coś takiego:

(cond 
    (= KeyEvent/VK_L key-value) 
    "Handle L" 
    (= KeyEvent/VK_M key-value) 
    "Handle M" 
    :else 
    "Handle some other key") 
6

zrobiłem małą bibliotekę Clojure, które przekłada pola publiczne Clojure mapy używając API refleksji:

(ns your.namespace 
(:use nl.zeekat.java.fields)) 

(deftype TestType 
    [field1 field2]) 

; fully dynamic: 

(fields (TestType. 1 2)) 
=> {:field1 1 :field2 2} 

; optimized for specific class: 
(def-fields rec-map TestType) 

(rec-map (TestType. 1 2)) 
=> {:field1 1 :field2 2} 

Zobacz https://github.com/joodie/clj-java-fields