2012-03-17 30 views
21

Tôi có một tệp có chứa 10 dòng - Tôi muốn truy xuất nó, sau đó chia chúng với dấu phân tách dòng mới ("\ n").Sự khác nhau giữa toString và mkString trong scala là gì?

đây là những gì tôi đã làm

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

Nhưng điều này gây ra một lỗi khi tôi cố gắng để phân chia các tập tin trên dòng mới.

sau đó tôi đã cố gắng

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

Và nó làm việc.

Cái quái gì? Ai đó có thể cho tôi biết sự khác biệt giữa hai phương pháp là gì?

+13

FYI, không ai viết các dấu chấm phẩy đó ở cuối dòng. –

+0

Bạn có gặp sự cố khi tìm các tài liệu liên quan không? Họ cho bạn biết chính xác sự khác biệt là gì. Bước đầu tiên là định vị chúng trên hệ thống tập tin cục bộ của bạn và đánh dấu chúng trong trình duyệt của bạn. –

+4

Thật sự, 'toString' là một phương pháp gỡ lỗi. Đó là mục đích thực sự là làm cho tất cả các đối tượng có thể in được, do đó các thông báo gỡ lỗi/gỡ rối sẽ có thể hiển thị một cái gì đó. –

Trả lời

23

Phương thức toString được cho là trả về biểu diễn chuỗi của một đối tượng. Nó thường được ghi đè để cung cấp một đại diện có ý nghĩa. Phương thức mkString được định nghĩa trên các bộ sưu tập và là một phương thức kết hợp các phần tử của bộ sưu tập với chuỗi được cung cấp. Ví dụ: hãy thử một cái gì đó như:

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

và bạn sẽ nhận được "a: b: c" làm đầu ra. Phương thức mkString đã tạo một chuỗi từ bộ sưu tập của bạn bằng cách nối các phần tử của bộ sưu tập với chuỗi bạn đã cung cấp. Trong trường hợp cụ thể bạn đã đăng, cuộc gọi mkString đã kết hợp các phần tử được trình lặp BufferedSource trả về với chuỗi rỗng (điều này là do bạn đã gọi mkString không có đối số). Kết quả này chỉ đơn giản là nối tất cả các chuỗi (được tạo bởi bộ đệm lặp BufferedSource) trong bộ sưu tập với nhau.

Mặt khác, gọi toString ở đây không thực sự có ý nghĩa, như những gì bạn đang nhận được (khi bạn không nhận được một lỗi) là biểu diễn chuỗi của trình vòng lặp BufferedSource; chỉ cho bạn biết rằng trình lặp không trống.

+0

"biểu diễn chuỗi của một đối tượng" âm thanh một chút như thể có một cách khách quan, mỗi đối tượng được biểu diễn. Trong thực tế, có một phương thức ".toString()" được định nghĩa trong java.lang.Object, được sử dụng nếu lớp hoặc cha mẹ trung gian không ghi đè lên nó. Ngược lại, mkString chỉ được định nghĩa trong vài lớp sưu tập của Scala. Và họ không tạo ra kết quả tương tự, như câu hỏi chỉ ra. mkString được định nghĩa theo cách hữu ích cho dữ liệu 'data: scala.io.BufferedSource = non-empty iterator', toString() không nhiều. –

1

Chúng là các phương pháp khác nhau trong các lớp khác nhau. Trong trường hợp này, mkString là một phương thức trong đặc tính GenTraversableOnce. toString được định nghĩa trên bất kỳ (và thường bị ghi đè).

Cách dễ nhất (hoặc ít nhất là cách tôi thường sử dụng) để tìm hiểu điều này là sử dụng tài liệu tại http://www.scala-lang.org/api/current/index.html. Bắt đầu với những loại biến của bạn:

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

là loại

scala.io.BufferedSource 

đi đến doc cho BufferedSource, và tìm kiếm mkString. Trong doc cho mkString (nhấn mũi tên xuống phía bên trái), bạn sẽ thấy rằng nó xuất phát từ

Definition Classes TraversableOnce → GenTraversableOnce 

Và làm điều tương tự với toString.

30

Hãy xem xét các loại, phải không?

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

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

scala> 

Bây giờ, biến mà bạn đã đọc tệp foo.txt thành một trình lặp. Nếu bạn thực hiện yêu cầu toString() trên đó, nó không trả lại nội dung của tệp, thay vì biểu diễn chuỗi của trình lặp mà bạn đã tạo.OTOH, mkString() đọc trình vòng lặp (nghĩa là, lặp qua nó) và xây dựng một chuỗi dài dựa trên các giá trị được đọc từ nó.

Mọi chi tiết, nhìn vào giao diện điều khiển phiên này:

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> 
+4

+1 cho phần giới thiệu về phong cách Simon Peyton-Jones :) – adamnfish

0

Tôi nghĩ vấn đề là phải hiểu những gì lớp Nguồn đang làm. Có vẻ như từ mã của bạn mà bạn mong đợi rằng Source.fromFile truy xuất nội dung của một tệp khi thực sự những gì nó làm là trỏ đến phần đầu của một tệp. Đây là điển hình khi làm việc với các hoạt động I/O, nơi bạn phải mở một "kết nối" với một tài nguyên (trong trường hợp này là kết nối với hệ thống tập tin của bạn), đọc/ghi nhiều lần và sau đó đóng "kết nối" đó. Trong ví dụ của bạn, bạn mở một kết nối đến một tập tin và bạn phải đọc dòng trên mỗi dòng nội dung của tập tin cho đến khi bạn đạt đến kết thúc. Hãy suy nghĩ rằng khi bạn đọc bạn đang tải thông tin trong bộ nhớ vì vậy không nên tải toàn bộ tệp trong bộ nhớ trong hầu hết các trường hợp (mà mkString sẽ làm).

Mặt khác mkString được thực hiện để lặp qua tất cả các phần tử của một bộ sưu tập, vì vậy trong trường hợp này, điều cần làm là đọc tệp và tải một mảng [String] trong bộ nhớ. Hãy cẩn thận vì nếu tệp lớn, mã của bạn sẽ thất bại, bình thường khi làm việc với I/O bạn nên sử dụng bộ đệm để đọc một số nội dung, sau đó xử lý/lưu nội dung đó và sau đó tải thêm nội dung (trong cùng bộ đệm), tránh các vấn đề với bộ nhớ. Ví dụ đọc 5 dòng -> phân tích cú pháp -> lưu các dòng được phân tích cú pháp -> đọc 5 dòng tiếp theo -> v.v.

Bạn cũng có thể hiểu rằng "toString" không truy xuất được gì ... chỉ nói với bạn "bạn có thể đọc dòng, tệp không trống ".

Các vấn đề liên quan