В чем разница между toString и mkString в Scala? - PullRequest
24 голосов
/ 17 марта 2012

У меня есть файл, который содержит 10 строк - я хочу получить его, а затем разделить их разделителем новой строки ("\ n").

вот что я сделал

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

Но это вызывает ошибку, когда я пытаюсь разбить файл на новые строки.

Я тогда попробовал

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

И это сработало.

Какого черта? Может кто-нибудь сказать мне, в чем разница между этими двумя методами?

Ответы [ 4 ]

34 голосов
/ 17 марта 2012

Давайте посмотрим на типы, не так ли?

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

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

scala> 

Теперь переменная, в которую вы прочитали файл foo.txt, является итератором.Если вы выполните toString() вызов для него, он не вернет содержимое файла, а String представления созданного вами итератора.OTOH, mkString() читает итератор (то есть перебирает его) и создает длинную строку на основе значений, прочитанных из него.

Для получения дополнительной информации посмотрите этот сеанс консоли:

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> 
26 голосов
/ 17 марта 2012

Предполагается, что метод toString возвращает строковое представление объекта.Это часто отменяется, чтобы обеспечить значимое представление.Метод mkString определен для коллекций и является методом, который объединяет элементы коллекции с предоставленной строкой.Например, попробуйте что-то вроде:

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

, и вы получите «a: b: c» в качестве вывода.Метод mkString создал строку из вашей коллекции, соединив элементы коллекции с предоставленной вами строкой.В конкретном случае, который вы разместили, вызов mkString соединил элементы, возвращаемые итератором BufferedSource, с пустой строкой (это потому, что вы вызвали mkString без аргументов).Это приводит к простой конкатенации всех строк (полученных итератором BufferedSource) в коллекции.

С другой стороны, вызов toString здесь на самом деле не имеет смысла, как то, что вы получаете (когда выне получить ошибку) является строковым представлением итератора BufferedSource;который просто говорит вам, что итератор не пустой.

2 голосов
/ 17 марта 2012

Это разные методы в разных классах.В этом случае mkString является методом в признаке GenTraversableOnce.toString определено для Any (и очень часто переопределяется).

Самый простой способ (или, по крайней мере, способ, которым я обычно использую), чтобы выяснить это, состоит в использовании документации на http://www.scala -lang.org / апи / ток / index.html .Начните с типа вашей переменной:

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

имеет тип

scala.io.BufferedSource

Перейдите в документ для BufferedSource и найдите mkString.В документе для mkString (нажмите стрелку вниз влево), вы увидите, что оно исходит от

Definition Classes TraversableOnce → GenTraversableOnce

И проделайте то же самое с toString.

1 голос
/ 26 июля 2016

Мне кажется, проблема в том, чтобы понять, что делает класс Source.Из вашего кода вы ожидаете, что Source.fromFile извлекает содержимое файла, когда в действительности он указывает на начало файла.

Это типично при работе с операциями ввода-вывода, когдаВы должны открыть «соединение» с ресурсом (в данном случае соединение с вашей файловой системой), прочитать / записать несколько раз, а затем закрыть это «соединение».В вашем примере вы открываете соединение с файлом, и вы должны читать строку за строкой содержимое файла, пока не дойдете до конца.Подумайте, что когда вы читаете, вы загружаете информацию в память, поэтому не стоит загружать весь файл в память в большинстве сценариев (что собирается делать mkString).

С другой стороны, mkStringсделано для итерации по всем элементам коллекции, поэтому в данном случае нужно прочитать файл и загрузить массив [String] в память.Будьте осторожны, потому что, если файл большой, ваш код потерпит неудачу, обычно при работе с вводом / выводом вы должны использовать буфер для чтения некоторого контента, затем обрабатывать / сохранять этот контент и затем загружать больше контента (в тот же буфер), избегая проблемс памятью.Например, чтение 5 строк -> анализ -> сохранение проанализированных строк -> чтение следующих 5 строк -> и т. Д.

Вы также можете понять, что toString ничего не возвращает ... просто говорит вам«Вы можете читать строки, файл не пустой».

...