Bu soruya baktım ama yine de Yinelenebilir ve Geçilebilir özellikler arasındaki farkı anlamadım. Biri açıklayabilir mi?
Yanıtlar:
Basitçe ifade etmek gerekirse, yineleyiciler durumu korurlar, geçişler yapmaz.
Bir Traversable
tek ö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 Iterable
has as as abstract method iterator
, bu da bir Iterator
. Seçtiğiniz zamanda next
bir Iterator
sonraki öğeyi almak için bir çağırabilirsiniz . Siz bunu yapana kadar, koleksiyonun neresinde olduğunu ve sırada ne olduğunu takip etmesi gerekiyor.
Iterable
genişliyor Traversable
, yani sanırım Traversable
s değil Iterable
s demek istiyorsun .
Traversable
arayüze uymak, arayüze uyurken durumu korumayı gerektirmez Iterator
.
Traversable
Iterable
yineleme durumunu korumayan s . Bu oluyor Iterator
oluşturulan ve döndürdüğü Iterable
durumunu tutar.
Bunu üfleme ve emme arasındaki fark olarak düşünün.
Bir Traversable
s'yi foreach
veya türetilmiş yöntemlerini çağırdığınızda , değerlerini işlevinize birer birer üfler - böylece yineleme üzerinde kontrol sahibi olur.
Bir Iterator
düşünce tarafından geri döndürüldüğünde, bir Iterable
sonrakine ne zaman geçeceğinizi kendiniz kontrol ederek değerleri ondan emersiniz.
tl, dr Iterables
olan Traversables
bu durum bilgisi üretebilirIterators
Öncelikle, bunun alt özelliği Iterable
olduğunu bilin Traversable
.
İkinci,
Traversable
foreach
her şey tarafından kullanılan yöntemin uygulanmasını gerektirir .
Iterable
iterator
her şey tarafından kullanılan yöntemin uygulanmasını gerektirir .
Örneğin, uygulaması find
için Traversable
kullanımları foreach
(anlama için bir cihaz aracılığıyla) ve atar BreakControl
tatmin 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 Iterator
eleman 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
}
}
Traversable
Yineleme 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ı Iterable
kolayca uygulayabileceğiniz için daha zorlu / güçlü özelliktir , ancak kullanmayı gerçekten uygulayamazsınız .foreach
iterator
iterator
foreach
Özet olarak, Iterable
bir 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
.
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
Traversable
içinde Scala 2.13 (halen kaldırılmış bir takma ad olarak tutulurIterable
2.14 kadar)