2010-07-02 4 views
8

Tutti,Scala - come scegliere in modo esplicito il metodo da utilizzare quando si arg deve essere nullo sovraccarico?

Sto eseguendo alcune manipolazioni di immagini in Scala facendo uso di oggetti BufferedImages e Raster. Sto cercando di ottenere tutti i pixel nell'immagine bufferizzata con il seguente codice.

val raster = f.getRaster() 

// Preallocating the array causes ArrayIndexOutOfBoundsException .. http://forums.sun.com/thread.jspa?threadID=5297789 
// RGB channels; 
val pixelBuffer = new Array[Int](width*height*3) 
val pixels = raster.getPixels(0,0,width,height,pixelBuffer) 

Ora, quando leggo in file relativamente grandi, questo funziona correttamente. Quando ho letto in 20x20 file PNG, ottengo un ArrayIndexOutOfBoundsException:

java.lang.ArrayIndexOutOfBoundsException: 1200 
at sun.awt.image.ByteInterleavedRaster.getPixels(ByteInterleavedRaster.java:1050) 

Ho letto online che il modo per aggirare questo problema è quello di non preallocare il pixelBuffer, ma invece di passare a un valore nullo e uso quello restituito dal metodo Raster.getPixels.

Ecco il mio problema. Quando faccio l'approccio ingenuo e basta passare Nil come ultimo argomento:

val pixels = raster.getPixels(0,0,width,height,Nil) 

ottengo l'errore

error: overloaded method value getPixels with alternatives (Int,Int,Int,Int,Array[Double])Array[Double] <and> (Int,Int,Int,Int,Array[Float])Array[Float] <and> (Int,Int,Int,Int,Array[Int])Array[Int] cannot be applied to (Int,Int,Int,Int,Nil.type) 
val pixels = raster.getPixels(0,0,width,height,Nil) 

Così, ovviamente, il compilatore non può determinare quale dei due metodi che sto cercando di chiamare ; è ambiguo. Se stavo usando Java, avrei lanciato il null per rendere esplicito il mio intento. Non riesco a capire come ottenere lo stesso effetto in Scala. Le cose che ho provato:

val pixelBuffer:Array[Int] = Nil // Cannot instantiate an Array to Nil for some reason 
Nil.asInstanceOf(Array[Int]) // asInstanceOf is not a member of Nil 

Qualsiasi idea di come dire al compilatore esplicitamente che voglio il metodo con l'array Int come ultimo parametro piuttosto che un array di float?

EDIT: Come risposta precisa, mi è stato sempre Nil mescolato con null. Nil è una lista vuota. Vedere il seguente blog post

Inoltre, dovrei sottolineare che l'eccezione di array fuori limite è stata colpa mia (come spesso accade). Il problema era che stavo dando per scontato che il raster avesse 3 canali, ma la mia immagine aveva 4 canali, dato che l'avevo creata in quel modo. Io invece preallocare l'array come segue:

val numChannels = raster.getNumBands() 

val pixelBuffer = new Array[Int](width*height*numChannels) 
val pixels = raster.getPixels(minX,minY,width,height,pixelBuffer) 

Grazie per l'aiuto

risposta

15

(Supponendo che si desidera che la questione di come risolvere i sovraccarichi quando si ha bisogno di passare un null):

proprio come si farebbe in Java, attribuendo il tipo corrispondente al sovraccarico che si desidera richiamare (in Java che ci si lanci, ma è la stessa cosa: un'affermazione di tipo statico da assegnare al null):

scala> object O { def m(i: Int, s: String): String = s * i; def m(i: Int, l: List[String]): String = l.mkString(":") * i } 
defined module O 

scala> O.m(23, null) 
<console>:7: error: ambiguous reference to overloaded definition, 
both method m in object O of type (i: Int,l: List[String])String 
and method m in object O of type (i: Int,s: String)String 
match argument types (Int,Null) 
     O.m(23, null) 
     ^

scala> O.m(23, null: String) 
res4: String = nullnullnullnullnullnullnullnullnullnullnullnullnullnullnullnullnullnullnullnullnullnullnull 

scala> O.m(23, null: List[String]) 
java.lang.NullPointerException 
     at O$.m(<console>:5) 
     at .<init>(<console>:7) 
     at .<clinit>(<console>) 
     at RequestResult$.<init>(<console>:9) 
     at RequestResult$.<clinit>(<console>) 
     at RequestResult$scala_repl_result(<console>) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 
     at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$18.apply(Interpreter.scala:981) 
     at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$18.apply(Interpreter.scala:981) 
     at scala.util.control.Exception$Catch.apply(Exception.scala:7... 
scala> 
+0

Questa è una spiegazione perfetta. Grazie – I82Much

+6

Preferirei che ha spiegato che attribuendo significa chosing quale dei possibili tipi che si desidera un valore di assumere, mentre lancia costringe un valore in un altro tipo, che può o non può prendere. –

5

confuso Nil con null.

+0

sì l'ho fatto. - Buon punto. Come ho detto nella mia modifica, il seguente post mi ha aiutato a risolvere: http://javaforyou.wordpress.com/2009/07/12/nothingness/ – I82Much

Problemi correlati