2012-03-17 29 views
21

Tengo un archivo que contiene 10 líneas: quiero recuperarlo y luego dividirlo con un delimitador de nueva línea ("\ n").¿Cuál es la diferencia entre toString y mkString en scala?

aquí es lo que hice

val data = io.Source.fromFile("file.txt").toString; 

Pero esto provoca un error cuando trato de dividir el archivo en nuevas líneas.

Luego probé

val data = io.Source.fromFile("file.txt").mkString; 

y funcionó.

¿Qué diablos? ¿Puede alguien decirme cuál es la diferencia entre los dos métodos?

+13

FYI, nadie escribe esos puntos y comas al final de la línea. –

+0

¿Ha tenido algún problema para encontrar los documentos relevantes? Te dicen exactamente cuál es la diferencia. El primer paso es ubicarlos en su sistema de archivos local y marcarlos en su navegador. –

+4

A decir verdad, 'toString' es un método de depuración. Su verdadero propósito es hacer que todos los objetos sean imprimibles, para que los depuradores/depuradores puedan mostrar algo. –

Respuesta

23

Se supone que el método toString devuelve la representación de cadena de un objeto. A menudo se anula para proporcionar una representación significativa. El método mkString se define en las colecciones y es un método que une los elementos de la colección con la cadena proporcionada. Por ejemplo, intente algo como:

val a = List("a", "b", "c") 
println(a.mkString(" : ")) 

y obtendrá "a: b: c" como salida. El método mkString ha creado una cadena de su colección uniendo los elementos de la colección con la cadena que proporcionó. En el caso particular que publicó, la llamada mkString se unió a los elementos devueltos por el iterador BufferedSource con la cadena vacía (esto se debe a que llamó a mkString sin argumentos). Esto da como resultado simplemente concatenar todas las cadenas (producidas por el iterador BufferedSource) en la colección juntas.

Por otro lado, llamar a String aquí realmente no tiene sentido, ya que lo que obtienes (cuando no obtienes un error) es la representación de cadena del iterador de BufferedSource; que simplemente te dice que el iterador no está vacío.

+0

"la representación de cadena de un objeto" suena un poco como si hubiera una manera objetiva, cada objeto está representado. De hecho, hay un método ".toString()" definido en java.lang.Object, que se usa si la clase o un padre intermedio no lo sobreescribió. Por el contrario, mkString solo se define en algunas clases de colección de Scala. Y no producen el mismo resultado, como lo señala la pregunta. mkString se define de manera útil para 'data: scala.io.BufferedSource = iterator no vacío', toString() no mucho. –

1

Son métodos diferentes en diferentes clases. En este caso, mkString es un método en el rasgo GenTraversableOnce. toString se define en Cualquiera (y a menudo se reemplaza).

La manera más fácil (o al menos la forma en que suelo usar) de encontrar esto es usar la documentación en http://www.scala-lang.org/api/current/index.html. Empezar con el tipo de la variable:

val data = io.Source.fromFile("file.txt") 

es de tipo

scala.io.BufferedSource 

ir a la doc para BufferedSource, y buscar mkString. En el documento de mkString (golpear la flecha hacia abajo a la izquierda) verá que se trata de

Definition Classes TraversableOnce → GenTraversableOnce 

Y hace lo mismo con toString.

30

Echemos un vistazo a los tipos, ¿de acuerdo?

scala> import scala.io._ 
import scala.io._ 

scala> val foo = Source.fromFile("foo.txt") 
foo: scala.io.BufferedSource = non-empty iterator 

scala> 

Ahora, la variable que ha leído el archivo en foo.txt es un iterador. Si realiza la invocación toString(), no devuelve el contenido del archivo, en lugar de la representación de cadena del iterador que ha creado.OTOH, mkString() lee el iterador (es decir, itera sobre él) y construye una cadena larga basada en los valores leídos de ella.

Para obtener más información, mira esta sesión de consola:

scala> foo.toString 
res4: java.lang.String = non-empty iterator 

scala> res4.foreach(print) 
non-empty iterator 
scala> foo.mkString 
res6: String = 
"foo 
bar 
baz 
quux 
dooo 
" 

scala> 
+4

+1 para la introducción del estilo Simon Peyton-Jones :) – adamnfish

0

Creo que el problema es entender lo que está haciendo la clase Fuente. Parece de su código que espera que Source.fromFile recupere el contenido de un archivo cuando realmente lo que hace es apuntar al inicio de un archivo.

Esto es típico cuando se trabaja con operaciones de E/S donde tiene que abrir una "conexión" con un recurso (en este caso una conexión con su sistema de archivos), leer/escribir varias veces y luego cerrar esa "conexión". En su ejemplo, abre una conexión a un archivo y debe leer la línea por línea del contenido del archivo hasta que llegue al final. Piensa que cuando lees estás cargando información en la memoria, por lo que no es una buena idea cargar todo el archivo en la memoria en la mayoría de los escenarios (lo que mkString hará).

Por otro lado mkString está hecho para iterar sobre todos los elementos de una colección, por lo que en este caso lo que hace es leer el archivo y cargar una matriz [String] en la memoria. Tenga cuidado porque si el archivo es grande su código fallará, normalmente cuando trabaje con E/S debe usar un búfer para leer algún contenido, luego procesar/guardar ese contenido y luego cargar más contenido (en el mismo búfer), evitando problemas con memoria Por ejemplo, leer 5 líneas -> analizar -> guardar líneas analizadas -> leer las 5 líneas siguientes -> etc.

También puede entender que "toString" no le recupera nada ... solo le dice "usted puede leer líneas, el archivo no está vacío ".

Cuestiones relacionadas