2012-10-07 19 views
5

tengo algo de código Clojure que está tratando de Interop través de un par de capas de código Java (en este caso, java.nio.Path a través de java.nio.file.WatchEvent<?>:¿Cómo se puede escribir una sugerencia dentro de la macro de subprocesamiento (->)?

(defn unroll-event 
    [^WatchEvent event] 
    { :kind (.kind event) 
    :context (.context event) 
    :path (-> event .context .toAbsolutePath .toString)}) 

En este código, no tengo tipo insinuó event, de modo que lo haría Creo que debe ser capaz de averiguar lo que se supone .context para volver, y como tal, será capaz de averiguar lo que .toAbsolutePath y .toString hacer. Creo que en este caso, ya que .context se define ha de devolver un tipo genérico de T, me Me pregunto si puedo escribir la llamada al .context. He intentado solo preceder g ^java.nio.file.Path-.context y ^Path y ^String-.toAbsolutePath y toString, respectivamente, pero aún así obtener las advertencias:

Reflection warning, junkcode/core.clj:28 - reference to field toAbsolutePath can't be resolved. 
Reflection warning, junkcode/core.clj:28 - reference to field toString can't be resolved. 

¿hay algo que pueda hacer en este caso? ¿Es porque -> es una macro y existen reglas especiales para la tipificación de tipo dentro de eso?

+0

¿A qué se está expandiendo? Use 'clojure.walk/macroexpand-all' – noahlz

Respuesta

2

(-> x .blah ^String .bar) se expande, básicamente, a (^String .bar (.blah x)), que claramente no está donde usted quiere la pista. El punto es que la sugerencia de tipo no tiene un comportamiento especial en ningún contexto (p. Ej., Macros): solo se trata de metadatos aplicados a los símbolos del código fuente. En su ejemplo ->, no hay lugar en el que pueda colocar los metadatos en el formulario de entrada que hará que esté donde desea en el formulario de salida. Por lo tanto, necesita escribir otra forma, como (-> ^Path (.context event) .toAbsolutePath str), por ejemplo.

Además, Clojure's inferencer no sabe nada acerca de los tipos genéricos, por lo que un método que devuelve T se trata como un método que devuelve un objeto, lo que explica por qué necesita insinuarlo todo aquí.

0

No sé si este ha sido siempre el caso, pero en Clojure 1.4.0, 1.5.1 y 1.6.0, puede teclear-insinuar en cualquier punto en ->, siempre que use paréntesis:

user=> (set! *warn-on-reflection* true) 
true 
user=> (fn [^java.nio.file.WatchEvent e] 
     (-> e ^java.nio.file.Path .context .toAbsolutePath)) 
Reflection warning, /private/var/folders/9_/wdph6m796zzc8trzcbtcmhrn5bjpt0/T/form-init8364673644863044068.clj:1:35 - reference to field toAbsolutePath on java.lang.Object can't be resolved. 
#<user$eval1995$fn__1996 [email protected]> 
user=> ; but no warning if we do 
user=> (fn [^java.nio.file.WatchEvent e] 
     (-> e ^java.nio.file.Path (.context) .toAbsolutePath)) 
#<user$eval1999$fn__2000 [email protected]> 

La única diferencia es en los parens alrededor de .context.

Cuestiones relacionadas