web-dev-qa-db-ja.com

ScalaでのtoStringとmkStringの違いは何ですか?

10行を含むファイルがあります。それを取得して、newline( "\ n")区切り文字で分割します。

これが私がやったことです

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

しかし、改行でファイルを分割しようとすると、エラーが発生します。

私はそれから試しました

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

そしてそれはうまくいった。

一体何ですか?誰かが2つの方法の違いを教えてくれますか?

25
alan

タイプを見てみましょうか。

_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()呼び出しを実行すると、ファイルのcontentsは返されず、作成したイテレータの文字列表現が返されます。 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> 
_
35
S.R.I

ToStringメソッドは、オブジェクトの文字列表現を返すことになっています。多くの場合、意味のある表現を提供するためにオーバーライドされます。 mkStringメソッドはコレクションで定義され、コレクションの要素を提供された文字列と結合するメソッドです。たとえば、次のようなことを試してください:

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

出力として「a:b:c」が表示されます。 mkStringメソッドは、コレクションの要素を指定した文字列と結合することにより、コレクションから文字列を作成しました。投稿した特定のケースでは、mkString呼び出しは、BufferedSourceイテレータによって返された要素を空の文字列と結合しました(これは、引数なしでmkStringを呼び出したためです)。これにより、コレクション内のすべての文字列(BufferedSourceイテレータによって生成された)が単純に連結されます。

一方、ここでtoStringを呼び出しても、実際には意味がありません。エラーが発生しない場合は、BufferedSourceイテレータの文字列表現だからです。これは、イテレータが空ではないことを伝えるだけです。

27
nomad

それらはクラスが異なれば異なるメソッドです。この場合、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を探します。 mkStringのドキュメントで(左にある下矢印を押す)、それが

Definition Classes TraversableOnce → GenTraversableOnce

そして、toStringでも同じことを行います。

2
James Moore

問題は、Sourceクラスが何をしているかを理解することだと思います。あなたのコードから、Source.fromFileが実際に行うのはファイルの先頭を指すことである場合、Source.fromFileがファイルのコンテンツを取得すると期待しているようです。

これは、リソースとの「接続」(この場合はファイルシステムとの接続)を開き、数回読み取り/書き込みを行ってから、その「接続」を閉じる必要があるI/O操作で作業する場合に一般的です。あなたの例では、ファイルへの接続を開き、最後に到達するまでファイルの内容を行ごとに読み取る必要があります。読んだときに情報をメモリに読み込んでいるので、ほとんどのシナリオ(mkStringで実行する)でファイル全体をメモリに読み込むことはお勧めできません。

一方、mkStringはコレクションのすべての要素を反復処理するように作成されているため、この場合、ファイルを読み取り、メモリにArray [String]をロードします。ファイルが大きい場合、コードが失敗するので注意してください。通常、I/Oで作業するときは、バッファーを使用してコンテンツを読み取り、そのコンテンツを処理/保存してから、同じバッファーにさらに多くのコンテンツをロードして、問題を回避する必要があります。メモリ付き。たとえば、5行を読み取る->解析->解析した行を保存->次の5行を読み取る->など.

また、「toString」は何も取得しないことも理解できます。「行を読み取ることができ、ファイルが空ではない」ことを通知するだけです。

1
Carlos Verdes