В чем разница между toString и mkString в scala?
У меня есть файл, который содержит 10 строк - я хочу получить его, а затем разделить их с разделителем новой строки ( "\n" ).
вот что я сделал
val data = io.Source.fromFile("file.txt").toString;
Но это вызывает ошибку, когда я пытаюсь разбить файл на новые строки.
Затем я попробовал
val data = io.Source.fromFile("file.txt").mkString;
И это сработало.
Что, черт возьми? Может ли кто-нибудь сказать мне, какая разница между этими двумя методами?
Ответы
Ответ 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" ничего не получает... просто говорит вам "вы можете читать строки, файл не пуст".