Scala: Scala koleksiyonlarındaki Geçilebilir ve Yinelenebilir özellikler arasındaki fark nedir?


98

Bu soruya baktım ama yine de Yinelenebilir ve Geçilebilir özellikler arasındaki farkı anlamadım. Biri açıklayabilir mi?


2
Daha vardır Traversableiçinde Scala 2.13 (halen kaldırılmış bir takma ad olarak tutulur Iterable2.14 kadar)
Xavier Guihot

Yanıtlar:


121

Basitçe ifade etmek gerekirse, yineleyiciler durumu korurlar, geçişler yapmaz.

Bir Traversabletek özet yöntem var foreach. Aradığınızda foreach, koleksiyon geçilen işlevi tuttuğu tüm öğeleri birbiri ardına besleyecektir.

Öte yandan, bir Iterablehas as as abstract method iterator, bu da bir Iterator. Seçtiğiniz zamanda nextbir Iteratorsonraki öğeyi almak için bir çağırabilirsiniz . Siz bunu yapana kadar, koleksiyonun neresinde olduğunu ve sırada ne olduğunu takip etmesi gerekiyor.


4
Ama Iterablegenişliyor Traversable, yani sanırım Traversables değil Iterables demek istiyorsun .
Robin Green

4
@RobinGreen Demek istediğim, Traversablearayüze uymak, arayüze uyurken durumu korumayı gerektirmez Iterator.
Daniel C. Sobral

10
TraversableIterableyineleme durumunu korumayan s . Bu oluyor Iteratoroluşturulan ve döndürdüğü Iterabledurumunu tutar.
Graham Lea

2
2.13 itibarıyla Traversable özelliğinin kullanımdan kaldırıldığını belirtmekte fayda var. Stefan Zeiger'den alıntı yapacak olursak, "Traversable soyutlama mevcut kütüphanede ağırlığını taşımadı ve büyük olasılıkla yeni tasarımda yeniden ortaya çıkmayacak. Yapmak istediğimiz her şey Yinelenebilir ile ifade edilebilir."
Igor Urisman

226

Bunu üfleme ve emme arasındaki fark olarak düşünün.

Bir Traversables'yi foreachveya türetilmiş yöntemlerini çağırdığınızda , değerlerini işlevinize birer birer üfler - böylece yineleme üzerinde kontrol sahibi olur.

Bir Iteratordüşünce tarafından geri döndürüldüğünde, bir Iterablesonrakine ne zaman geçeceğinizi kendiniz kontrol ederek değerleri ondan emersiniz.


49
İnsanlar buna üflemek ve emmek yerine itme ve çekme derlerdi , ama ben senin açık fikirli olmanı seviyorum.
Martijn

2
Bir sonraki röportajımda sorulduğunda bunu asla unutmayacağım
thestephenstanton

23

tl, dr Iterables olan Traversablesbu durum bilgisi üretebilirIterators


Öncelikle, bunun alt özelliği Iterableolduğunu bilin Traversable.

İkinci,

  • Traversableforeachher şey tarafından kullanılan yöntemin uygulanmasını gerektirir .

  • Iterableiteratorher şey tarafından kullanılan yöntemin uygulanmasını gerektirir .

Örneğin, uygulaması findiçin Traversablekullanımları foreach(anlama için bir cihaz aracılığıyla) ve atar BreakControltatmin edici bir unsur bulunduktan sonra bir yineleme durdurmak için durum.

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
  }
}

Buna karşılık, Iterableçıkarma, bu uygulama ve aramaları geçersiz kılar findüzerinde Iteratoreleman bulunduğunda sadece yineleme durdurur:

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
  }
}

TraversableYineleme için istisnalar atmamak güzel olurdu , ancak yalnızca kullanırken kısmen yinelemenin tek yolu budur foreach.

Bir bakış açısına göre, kullanmayı Iterablekolayca uygulayabileceğiniz için daha zorlu / güçlü özelliktir , ancak kullanmayı gerçekten uygulayamazsınız .foreachiteratoriteratorforeach


Özet olarak, Iterablebir durum bilgisi aracılığıyla yinelemeyi duraklatmanın, devam ettirmenin veya durdurmanın bir yolunu sağlar Iterator. İle Traversable, hepsi ya da hiçbiri (akış kontrolü için istisnalar hariç).

Çoğu zaman önemli değildir ve daha genel bir arayüz isteyeceksiniz. Ancak yineleme üzerinde daha özelleştirilmiş kontrole ihtiyacınız olursa Iterator, bir Iterable.


1

Daniel'in cevabı kulağa hoş geliyor. Bakalım kendi sözlerimle ifade edebilecek miyim?

Böylece, Yinelemeli size bir yineleyici verebilir, bu, öğeleri birer birer geçmenize (next () kullanarak) ve istediğiniz gibi durup gitmenize olanak tanır. Bunu yapmak için yineleyicinin, elemanın konumuna dahili bir "işaretçi" tutması gerekir. Ancak bir Traversable size foreach, tüm öğeleri aynı anda durmadan çaprazlama yöntemini verir.

Range (1, 10) gibi bir şey, Traversable olarak durum olarak yalnızca 2 tam sayıya sahip olmalıdır. Ancak Yinelenebilir olarak Range (1, 10) size durum için 3 tamsayı kullanması gereken bir yineleyici verir, bunlardan biri indeksdir.

Traversable'ın ayrıca foldLeft, foldRight da sunduğunu düşünürsek, foreach'in öğeleri bilinen ve sabit bir sırayla çaprazlaması gerekir. Bu nedenle, Traversable için bir yineleyici uygulamak mümkündür. Örneğin, def iterator = toList.iterator

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.