Scala: Apa perbedaan antara ciri Traversable dan Iterable dalam koleksi Scala?

98

Saya telah melihat pertanyaan ini tetapi masih tidak memahami perbedaan antara sifat Iterable dan Traversable. Bisakah seseorang menjelaskan?

Rahul
sumber
2
Tidak ada lagi Traversabledi Scala 2.13 (ini masih disimpan sebagai alias yang tidak digunakan lagi Iterablehingga 2.14)
Xavier Guihot

Jawaban:

121

Sederhananya, iterator mempertahankan status, tidak dapat dilintasi.

Sebuah Traversablememiliki satu metode abstrak: foreach. Saat Anda memanggil foreach, collection akan memberi makan fungsi yang diteruskan semua elemen yang disimpannya, satu demi satu.

Di sisi lain, metode Iterablehas as abstrak iterator, yang mengembalikan Iterator. Anda dapat memanggil nextpada Iteratoruntuk mendapatkan elemen berikutnya pada waktu yang Anda pilih. Sampai Anda melakukannya, itu harus melacak di mana itu dalam koleksi, dan apa selanjutnya.

Daniel C. Sobral
sumber
4
Tapi Iterablemeluas Traversable, jadi saya rasa maksud Anda Traversables yang bukan Iterables.
Robin Green
4
@RobinGreen Maksud saya, mematuhi Traversableantarmuka tidak memerlukan status penyimpanan, sementara mematuhi Iteratorantarmuka memerlukannya .
Daniel C. Sobral
10
Traversables yang Iterabletidak menyimpan status iterasi apa pun. Itu Iteratordibuat dan dikembalikan oleh Iterableyang menjaga negara.
Graham Lea
1
Patut dicatat bahwa mulai 2.13 ciri Traversable tidak digunakan lagi. Mengutip Stefan Zeiger, "Abstraksi yang dapat dilintasi belum membawa bobotnya di perpustakaan saat ini dan kemungkinan besar tidak akan muncul kembali dalam desain baru. Semua yang ingin kami lakukan dapat diekspresikan dengan Iterable."
Igor Urisman
226

Anggap saja sebagai perbedaan antara meniup dan menghisap.

Ketika Anda memiliki panggilan Traversables foreach, atau metode turunannya, itu akan meledakkan nilainya ke dalam fungsi Anda satu per satu - sehingga ia memiliki kendali atas iterasi.

Dengan pengembalian Iteratoroleh Iterablemeskipun, Anda menyedot nilai darinya, mengontrol kapan harus pindah ke yang berikutnya sendiri.

Duncan McGregor
sumber
49
Orang biasa menyebut ini mendorong dan menarik daripada meniup dan menghisap , tapi saya suka keterbukaan pikiran Anda.
Martijn
2
Jangan pernah melupakan ini ketika ditanya dalam wawancara saya berikutnya
thestephenstanton
23

tl; dr Iterables adalah Traversablesyang dapat menghasilkan statefulIterators


Pertama, ketahuilah bahwa itu Iterableadalah inti dari Traversable.

Kedua,

  • Traversablemembutuhkan penerapan foreachmetode, yang digunakan oleh yang lainnya.

  • Iterablemembutuhkan penerapan iteratormetode, yang digunakan oleh yang lainnya.

Misalnya, implementasi findfor Traversableuse foreach(melalui pemahaman for) dan melontarkan BreakControlpengecualian untuk menghentikan iterasi setelah elemen yang memuaskan ditemukan.

trait TravserableLike {
  def find(p: A => Boolean): Option[A] = {
    var result: Option[A] = None
    breakable {
      for (x <- this)
        if (p(x)) { result = Some(x); break }
    }
    result
  }
}

Sebaliknya, Iterablekurangi menimpa implementasi ini dan panggilan findpada Iterator, yang hanya berhenti iterasi sekali unsur ini ditemukan:

trait Iterable {
  override /*TraversableLike*/ def find(p: A => Boolean): Option[A] =
    iterator.find(p)
}

trait Iterator {
  def find(p: A => Boolean): Option[A] = {
    var res: Option[A] = None
      while (res.isEmpty && hasNext) {
        val e = next()
        if (p(e)) res = Some(e)
      }
    res
  }
}

Akan lebih baik untuk tidak membuang pengecualian untuk Traversableiterasi, tetapi itulah satu-satunya cara untuk mengulang sebagian saat menggunakan just foreach.

Dari satu perspektif, Iterableadalah sifat yang lebih menuntut / kuat, karena Anda dapat dengan mudah menerapkan foreachmenggunakan iterator, tetapi Anda tidak dapat benar-benar menerapkan iteratormenggunakan foreach.


Singkatnya, Iterablemenyediakan cara untuk menjeda, melanjutkan, atau menghentikan iterasi melalui stateful Iterator. DenganTraversable , itu semua atau tidak sama sekali (tanpa pengecualian untuk kontrol aliran).

Seringkali tidak masalah, dan Anda pasti menginginkan antarmuka yang lebih umum. Tetapi jika Anda membutuhkan lebih banyak kontrol yang disesuaikan atas iterasi, Anda akan memerlukan Iterator, yang dapat Anda ambil dari file Iterable.

Paul Draper
sumber
1

Jawaban Daniel kedengarannya bagus. Biarkan saya melihat apakah saya bisa menjelaskannya dengan kata-kata saya sendiri.

Jadi Iterable dapat memberi Anda iterator, yang memungkinkan Anda melintasi elemen satu per satu (menggunakan next ()), dan berhenti dan pergi sesuka Anda. Untuk melakukan itu, iterator perlu menyimpan "penunjuk" internal ke posisi elemen. Namun Traversable memberi Anda metode, foreach, untuk melintasi semua elemen sekaligus tanpa henti.

Sesuatu seperti Range (1, 10) hanya perlu memiliki 2 integer sebagai status Traversable. Tapi Range (1, 10) sebagai Iterable memberi Anda iterator yang perlu menggunakan 3 integer untuk state, salah satunya adalah index.

Mempertimbangkan bahwa Traversable juga menawarkan foldLeft, foldRight, foreachnya perlu melintasi elemen dalam urutan yang diketahui dan tetap. Oleh karena itu, mungkin untuk mengimplementasikan iterator untuk Traversable. Misalnya def iterator = toList.iterator

pengguna11595225
sumber