2010-06-17 19 views
30

utilizo opencsv para analizar archivos csv, y mi código esUnidad Scala tipo

while((line = reader.readNext()) != null) { .... } 

Tengo una advertencia del compilador diciendo:

comparing values of types Unit and Null using `!=' will always yield true 
[warn]  while((aLine = reader.readNext()) != null) { 

¿Cómo debo hacer el bucle while?

Respuesta

17

En su caso (line = reader.readNext()) es un literal funcional que devuelve el tipo Unit. Es posible volver a escribir el código de la siguiente manera:

while({line = reader.readNext(); line!= null}) { .... } 
+8

Por favor, no acepte esta respuesta: si bien es cierto que Scala no es idiomático y hay formas mucho mejores de lograr lo que quiere (vea mi respuesta a continuación) –

+3

@oxbow_lakes, ¿quizás está siendo un poco severo aquí? La palabra clave while se usa cientos de veces en la biblioteca estándar 2.8 por el equipo central y esta respuesta es completa, concisa y, lo que es más importante, se parece a mi respuesta; @)) –

+10

Me atengo al comentario, me temo. Esto no es idiomáticoNo es incluso más rendimiento que las respuestas * funcionales * porque su código se compilará en una instancia de función (es decir, objeto) –

3

La asignación en Scala no devuelve un valor, la unidad es similar a void en C o C++.

tratar

var line = "" 

while ({line = reader.readNext(); line != null}) { ... } 

Esto funciona porque el valor de la última expresión en un bloque se devuelve y en este caso se trata de un booleano que es requerido por la mientras

+1

'unit' en Scala es más similar a' 'void' que a null'. – Jesper

+0

Buen punto gracias, corregiré lo anterior. –

67

expresión Una asignación tiene tipo Unit en Scala. Esa es la razón de su advertencia de compilación.

Hay una bonita idioma en el Scala que evita el bucle while:

val iterator = Iterator.continually(reader.readNext()).takeWhile(_ != null) 

Esto le da un iterador sobre cualquier reader.readNext devoluciones.

El método continually devuelve un iterador "infinito" y takeWhile toma el prefijo de eso, hasta el primer nulo, pero sin incluirlo.

(Scala 2.8)

+0

Hmm. Mi respuesta realmente no coincide con la pregunta. Lo conservaré, podría ser útil de todos modos. – mkneissl

+0

¿Por qué crees que tu respuesta no coincide con la pregunta? –

+0

@Ken: portoalet pidió una explicación para la advertencia sobre la Unidad. Respondí con un modismo de bucle. Acabo de agregar la explicación de la advertencia para completar la respuesta. – mkneissl

9

está escribiendo código Scala que la forma que se escribirían en Java. Intenta hacerlo de una manera más similar a Scala. Para leer una línea de archivo de texto por línea y hacer algo con cada línea, intente esto:

import java.io.File 
import scala.io.Source 

Source.fromFile(new File("myfile.txt")).getLines.foreach { line => 
    // Do something with the line, for example print it 
    println(line) 
} 
+0

No está haciendo IO de archivo sin formato. Él está haciendo CSV IO. –

+0

@Ken Los archivos CSV normalmente son archivos de texto orientados a la línea, y su fragmento de código anterior trata de leer un archivo de texto línea por línea. Mi respuesta, de hecho, no es una respuesta directa a su pregunta, solo quería mostrar una forma que se ajuste más al idioma de Scala; su código original es el idioma de Java en Scala. – Jesper

17

Se puede utilizar un Stream para conseguir lo que quiere:

Stream.continually(reader.readLine()).takeWhile(_ ne null) foreach { line => 
    //do Stuff 
} 

Esto tiene la ventaja añadida de otra cosas interesantes, así:

Stream.continually(reader.readLine()).takeWhile(_ ne null) match { 
    case head #:: tail => //perhaps you need to do stuff with the first element? 
    case _    => //empty 
} 

EDITAR - gracias a mkneissl por señalar que debería haber incluido esta advierten ING:

scala> Stream.continually(1).take(100000000).foreach(x=>()) 

scala> val s = Stream.continually(1).take(100000000) 
s: scala.collection.immutable.Stream[Int] = Stream(1, ?) 

scala> s.foreach(x=>()) java.lang.OutOfMemoryError: Java heap space 
+3

Es posible que desee agregar una advertencia para no mantener el encabezado del flujo para evitar quedarse sin memoria. Han sido atrapados por esto recientemente al leer archivos enormes. Scala> Stream.continually (1) .take (100,000,000) .foreach (x =>()) está bien, pero Scala> val s = Stream.continually (1) .take (100000000) s : scala.collection.immutable.Stream [Int] = corriente (1,?) Scala> s.foreach (x =>()) java.lang.OutOfMemoryError: Java espacio de montón [bah, sin formato en los comentarios , vea pastie: http://paste.pocoo.org/show/226682/] – mkneissl

+2

A menos que realmente necesite un Stream, también podría usar Iterator.continually en lugar de Stream.continually, entonces no tiene preocupaciones por problemas con Stream . –

+1

Right Seth, vea mi respuesta a esta pregunta: http://stackoverflow.com/questions/3062804/scala-unit-type/3063092#3063092 y para una comparación de Stream vs. Iterator, consulte http://stackoverflow.com/ preguntas/1527962/difference-between-iterator-and-stream-in-scala. – mkneissl