2010-06-10 34 views
24

¿Cuál es el "correcto" de escribir el ciclo estándar de lectura/lectura en Scala? Por apropiado me refiero a escrito en una forma similar a Scala en comparación con una forma de Java.¿Cuál es la forma correcta de codificar un ciclo de lectura en Scala?

Aquí está el código que tengo en Java:

MessageDigest md = MessageDigest.getInstance("MD5"); 
InputStream input = new FileInputStream("file"); 
byte[] buffer = new byte[1024]; 
int readLen; 
while((readLen = input.read(buffer)) != -1) 
    md.update(buffer, 0, readLen); 
return md.digest(); 

Aquí está el código que tengo en Scala:

val md = MessageDigest.getInstance(hashInfo.algorithm) 
val input = new FileInputStream("file") 
val buffer = new Array[ Byte ](1024) 
var readLen = 0 
while(readLen != -1) 
{ 
    readLen = input.read(buffer) 
    if(readLen != -1) 
     md.update(buffer, 0, readLen) 
} 
md.digest 

El código Scala es correcto y funciona, pero se siente muy poco Scala -ish. Para uno, es una traducción literal del código de Java, sin aprovechar ninguna de las ventajas de Scala. ¡Además es más largo que el código de Java! Realmente siento que me estoy perdiendo algo, pero no puedo entender qué.

Soy bastante nuevo en Scala, por lo que estoy haciendo la pregunta para evitar caer en la trampa de escribir código de estilo Java en Scala. Estoy más interesado en la forma de Scala para resolver este tipo de problema que en cualquier otro método de ayuda específico que pueda proporcionar la API de Scala para el hash de un archivo.

(Me disculpo de antemano por mis hoc adjetivos ad Scala en toda esta cuestión.)

+4

Mi respuesta a http://stackoverflow.com/questions/2849303 puede ser útil. –

+5

@Rex Yo usaría 'Iterator' en lugar de' Stream'. Después de todo, es de un solo disparo y no reutilizable. Además, 'Iterator' tiene mejor rendimiento de memoria en tales tareas. –

+0

@Daniel - De acuerdo. Creo que hubo una buena razón por la que utilicé 'Stream' anteriormente, pero ya no puedo recordar qué (y no creo que siga siendo así). De todos modos, aquí 'Iterator.continually' debería estar bien. –

Respuesta

25

Basado en el poste de Rex que él menciona:

Stream.continually(input.read(buffer)).takeWhile(_ != -1).foreach(md.update(buffer, 0, _)) 

debería cambiar sus var readLen +, mientras que {.. .} líneas con él, produce el mismo resultado.

Como mencionó Rex, funciona con scala 2.8.

+2

Si Stream te da los pelos de punta, también puedes usar Iterator.continually. –

+0

Cuando lo pruebo en un InputStream que obtuve de un Proceso, el método foreach se llama para el primer carácter y luego se detiene. Cuando se usa con while, obtengo todos los datos. ¿Alguna idea de por qué? – pommedeterresautee

+0

¿cómo obtengo la cantidad de bytes leídos desde "input.read (...)" para usarlo en "foreach"? –

7

Lo Rex Kerr sugiere en su comentario es el siguiente:

val md = MessageDigest.getInstance("MD5") 
val input = new FileInputStream("foo.txt") 
val buffer = new Array[ Byte ](1024) 
Stream.continually(input.read(buffer)) 
    .takeWhile(_ != -1) 
    .foreach(md.update(buffer, 0, _)) 
md.digest 

La clave es la Stream.continually. Obtiene una expresión que se evalúa continuamente, creando un infinito Stream de la expresión evaluada. El takeWhile es la traducción del while -condition. El foreach es el cuerpo del while -loop.

0

¿Qué tal una función al curry? Usted 11 líneas de código Scala se convierten en:

val md = MessageDigest.getInstance(hashInfo.algorithm) 
val input = new FileInputStream("file") 
iterateStream(input){ (data, length) => 
    md.update(data, 0, length) 
} 
md.digest 

La función iterateStream en la línea 3, que se podría añadir a una biblioteca es:

def iterateStream(input: InputStream)(f: (Array[Byte], Int) => Unit){ 
    val buffer = new Array[Byte](512) 
    var curr = input.read(buffer) 
    while(curr != -1){ 
     f(buffer, curr) 
     curr = input.read(buffer) 
    } 
} 

El código duplicado fea (donde se lee la entrada) de los extremos en la biblioteca, bien probado y escondido del programador. Siento que el primer bloque de código es menos complejo que la solución Iterator.continually.

Cuestiones relacionadas