it-swarm.com.de

Was ist der Unterschied zwischen toString und mkString in Scala?

Ich habe eine Datei mit 10 Zeilen - ich möchte sie abrufen und sie dann mit einem Trennzeichen für neue Zeilen ("\ n") teilen.

hier ist was ich getan habe

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

Dies verursacht jedoch einen Fehler, wenn ich versuche, die Datei in Zeilenumbrüche aufzuteilen.

Ich habe es dann versucht

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

Und es hat funktioniert.

Was zum Teufel? Kann mir jemand sagen, was der Unterschied zwischen den beiden Methoden ist?

22
alan

Schauen wir uns die Typen an, oder? 

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

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

scala> 

Nun ist die Variable, in die Sie die Datei foo.txt eingelesen haben, ein Iterator. Wenn Sie einen Aufruf von toString() ausführen, gibt es nicht den Inhalt der Datei zurück, sondern die String-Darstellung des von Ihnen erstellten Iterators. OTOH, mkString() liest den Iterator (d. H. Iteriert darüber) und erstellt einen langen String basierend auf den daraus gelesenen Werten. 

Weitere Informationen finden Sie in dieser Konsolensitzung:

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> 
33
S.R.I

Die toString-Methode soll die Zeichenfolgendarstellung eines Objekts zurückgeben. Es wird oft überschrieben, um eine sinnvolle Darstellung zu bieten. Die mkString-Methode ist für Sammlungen definiert und ist eine Methode, die die Elemente der Sammlung mit der bereitgestellten Zeichenfolge verbindet. Versuchen Sie zum Beispiel etwas wie:

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

und Sie erhalten "a: b: c" als Ausgabe. Die Methode mkString hat aus Ihrer Sammlung eine Zeichenfolge erstellt, indem Sie die Elemente der Sammlung mit der von Ihnen angegebenen Zeichenfolge verbinden. In dem von Ihnen geposteten Fall fügte der mkString-Aufruf die vom BufferedSource-Iterator zurückgegebenen Elemente mit der leeren Zeichenfolge zusammen (weil Sie mkString ohne Argumente aufgerufen haben). Dies führt dazu, dass einfach alle Zeichenfolgen (die der BufferedSource-Iterator ergibt) in der Auflistung miteinander verkettet werden.

Auf der anderen Seite macht das Aufrufen von toString keinen Sinn, da das, was Sie erhalten (wenn Sie keinen Fehler erhalten), die Zeichenfolgendarstellung des BufferedSource-Iterators ist; was Ihnen nur sagt, dass der Iterator nicht leer ist.

23
nomad

Sie sind unterschiedliche Methoden in verschiedenen Klassen. In diesem Fall ist mkString eine Methode in der Eigenschaft GenTraversableOnce. toString ist für Any definiert (und wird sehr oft überschrieben).

Der einfachste Weg (oder zumindest der Weg, den ich normalerweise benutze), um dies herauszufinden, ist die Verwendung der Dokumentation unter http://www.scala-lang.org/api/current/index.html . Beginnen Sie mit dem Typ Ihrer Variablen:

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

ist vom Typ

scala.io.BufferedSource

Gehen Sie zum Dokument für BufferedSource und suchen Sie nach mkString. In dem Dokument für mkString (den Pfeil nach unten nach links drücken) sehen Sie, dass es von kommt 

Definition Classes TraversableOnce → GenTraversableOnce

Und dasselbe mit toString.

1
James Moore

Ich denke, das Problem ist zu verstehen, was die Source-Klasse tut. In Ihrem Code scheint es, als würden Sie davon ausgehen, dass Source.fromFile den Inhalt einer Datei abruft, wenn sie wirklich auf den Anfang einer Datei zeigt.

Dies ist typisch, wenn Sie mit E/A-Vorgängen arbeiten, bei denen Sie eine "Verbindung" mit einer Ressource (in diesem Fall eine Verbindung mit Ihrem Dateisystem) öffnen müssen, mehrmals lesen/schreiben und dann diese "Verbindung" schließen. In Ihrem Beispiel öffnen Sie eine Verbindung zu einer Datei, und Sie müssen Zeile für Zeile den Inhalt der Datei bis zum Ende lesen. Denken Sie beim Lesen daran, dass Sie Informationen in den Speicher laden. Daher ist es in den meisten Szenarien nicht sinnvoll, die gesamte Datei in den Speicher zu laden (was mkString tun wird).

Auf der anderen Seite wird mkString dazu veranlasst, alle Elemente einer Auflistung zu durchlaufen. In diesem Fall lesen Sie also die Datei und laden ein Array [String] in den Speicher. Seien Sie vorsichtig, denn wenn die Datei groß ist, schlägt der Code fehl. Normalerweise sollten Sie bei der Arbeit mit E/A einen Puffer zum Lesen von Inhalten verwenden, diesen Inhalt dann verarbeiten/speichern und dann weitere Inhalte laden (in demselben Puffer), um Probleme zu vermeiden mit Gedächtnis. Zum Beispiel 5 Zeilen lesen -> parsen -> geparste Zeilen speichern -> nächste 5 Zeilen lesen -> usw.

Sie können auch verstehen, dass "toString" Sie nichts abruft ... sagt Ihnen "Sie können Zeilen lesen, die Datei ist nicht leer".

0
Carlos Verdes