2012-09-27 22 views
6

Tại sao nó rằng,đồ Scala trên iterator không tạo ra tác dụng phụ

scala> List(1,2,3,4).iterator.map((x: Int) => println(x)) 

không in ra

1 
2 
3 
4 

khi

List(1,2,3,4).map((x: Int) => println(x)) 
List(1,2,3,4).foreach((x: Int) => println(x)) 
List(1,2,3,4).iterator.foreach((x: Int) => println(x)) 

tất cả làm gì?

Nói cách khác, tại sao bản đồ trên trình lặp lặp lại ánh xạ loại T thành đơn vị và có tác dụng phụ không thể hiển thị những tác dụng phụ đó?

Edit:

Cũng tại sao invocation sau lazyMap thực sự tính toán iterator mới (cung cấp các iterator mới hoàn thành) từ đầu đến cuối nếu iterator là lười biếng?

def lazyMap[T, U](coll: Iterable[T], f: T => U) = new Iterable[U] { 
    def iterator = coll.iterator map f 
} 

scala> lazyMap(List(1,2,3,4), (x: Int) => x + 1) 
res4: java.lang.Object with Iterable[Int] = (2, 3, 4, 5) 
+0

Bằng cách này, bạn đang làm sai phần mở rộng của Iterable (tất cả các lớp mở rộng Iterable nên cung cấp phương thức 'newBuilder') –

Trả lời

7

bản đồ Nguyên nhân trên iterator là lười biếng và bạn cần một số tính nghiêm minh:

scala> List(1,2,3,4).iterator.map((x: Int) => println(x)) 
res0: Iterator[Unit] = non-empty iterator 

// nothing actually happened yet, just remember to do this printing things 

scala> res0.toList 
1 
2 
3 
4 
res1: List[Unit] = List((),(),(),()) 

Khi bạn làm foreach trên iterator nó là khá rõ ràng rằng bạn đang làm có tác dụng phụ, vì vậy lazyness sẽ không mong muốn. Tôi sẽ không nói như vậy về bản đồ.

UPD

Đối với sửa đổi của bạn: Lý do cho hành vi như vậy, được rằng có cuộc gọi ngầm của toString cho kết quả tuyên bố mà lần lượt stricts iterator - thử mã này trên của riêng bạn:

scala> { lazyMap(List(1,2,3,4), {(x: Int) => println(x); x + 1}); 1 } 

và bạn sẽ thấy rằng chức năng f không bao giờ được gọi là

6

Mấu chốt của một Iterator là sự lười biếng. Nói cách khác, khi bạn tạo một Iterator, nó sẽ không đánh giá bất cứ thứ gì cho đến khi bạn đọc dữ liệu. Dưới đây là những gì trông giống như:

scala> val itr = List(1,2,3).iterator 
itr: Iterator[Int] = non-empty iterator 

Ok, chúng tôi hiện có một trình lặp. Nhưng nó chưa thực sự nhìn vào danh sách.

scala> val mappedItr = itr.map((x: Int) => println(x)) 
mappedItr: Iterator[Unit] = non-empty iterator 

Bây giờ chúng tôi có Iterator mới. Điều này sẽ, khi dữ liệu được truy cập, áp dụng các chức năng đã được ánh xạ. Nhưng chúng tôi vẫn còn chưa thực sự xem danh sách gốc.

scala> mappedItr.next 
1 

Đây là lần đầu tiên chúng tôi truy cập dữ liệu, vì vậy đây là lần đầu tiên Iterator nhìn vào danh sách. Chúng tôi gọi là next, vì vậy chúng tôi có yếu tố đầu tiên. Vì trình lặp của chúng ta có một hàng đợi map, nó áp dụng hàm được ánh xạ khi chúng ta truy cập phần tử đó. Vì vậy, chúng ta thấy kết quả của hàm được áp dụng cho mục next.

Chúng ta có thể làm điều đó một lần nữa để có được những yếu tố tiếp theo:

scala> mappedItr.next 
2 

Và, một lần nữa, nó đánh giá chức năng chỉ khi nó cần phải, để cho chúng ta những kết quả cuối cùng.

+0

vui lòng xem chỉnh sửa – platypus

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