Подтвердить что ты не робот

В чем разница между toString и mkString в scala?

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

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

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

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

Затем я попробовал

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

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

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

4b9b3361

Ответ 1

Посмотрим на типы, не так ли?

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() на нем, он не возвращает содержимое файла, а представляет собой строковое представление итератора, который вы создали. 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> 

Ответ 2

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

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

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

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

Ответ 3

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

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

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

имеет тип

scala.io.BufferedSource

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

Definition Classes TraversableOnce → GenTraversableOnce

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

Ответ 4

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

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

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

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