Scala:ScalaコレクションのTraversableとIterableトレイトの違いは何ですか?


回答:


121

簡単に言えば、イテレータは状態を保持しますが、走査可能オブジェクトは保持しません。

AにTraversableは1つの抽象メソッドがありますforeach。を呼び出すforeach、コレクションは渡された関数が保持するすべての要素を次々にフィードします。

一方、Iterablehas as abstract methodはiterator、を返しますIterator。を呼び出しnextて、Iterator選択時に次の要素を取得できます。あなたがそうするまで、それはそれがコレクションのどこにあったか、そして次は何を追跡する必要があります。


4
しかし、Iterable拡張されるTraversableので、私はあなたがTraversablesではないことを意味すると思いますIterable
Robin Green

4
@RobinGreen Traversableインターフェースに準拠している間は、状態を維持する必要はありませんが、インターフェースに準拠している必要がありIteratorます。
ダニエルC.ソブラル2013年

10
TraversablesはIterable反復状態を保持しません。それはだIterator作成されてから返されたIterable状態を維持しています。
Graham Lea 14

1
2.13以降、Traversableは非推奨になりました。Stefan Zeigerを引用すると、「Traversable抽象化は現在のライブラリではその重要性を生かしておらず、新しいデザインで再浮上することはおそらくありません。やりたいことはすべてIterableで表現できます。」
Igor Urisman

226

それを吹くと吸うの違いと考えてください。

Traversables foreachまたはその派生メソッドを呼び出すと、その値が一度に1つずつ関数に吹き込まれ、反復を制御できます。

でも、Iterator返されたIterable値を使用して、値を吸い取り、次の値に移動するタイミングを自分で制御します。


49
人々は、これを吹く吸うのではなく、押す引くと呼びますが、私はあなたのオープンマインドが好きです。
Martijn、

2
私の次のインタビューで尋ねられたときにこれを忘れないでください
thestephenstanton

23

tl; dr IterablesTraversablesステートフルを生成できるIterators


まず、それIterableがの下位特性であることを知ってくださいTraversable

第二に、

  • Traversableforeach他のすべてで使用されるメソッドを実装する必要があります。

  • Iterableiterator他のすべてで使用されるメソッドを実装する必要があります。

たとえば、findfor の実装Traversableforeach(for内包表記を介して)BreakControl、満足のいく要素が見つかると、例外をスローして反復を停止します。

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

対照的に、Iterable減算はこの実装をオーバーライドfindし、を呼び出します。これIteratorは、要素が見つかると反復を停止するだけです。

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反復のために例外をスローしないのは良いことですが、それだけがを使用して部分的に反復する唯一の方法foreachです。

1つの観点から見ると、を使用してIterable簡単に実装できますが、実際にを使用して実装することはできません。foreachiteratoriteratorforeach


要約するとIterable、ステートフルを介して反復を一時停止、再開、または停止する方法を提供しますIterator。を使用するとTraversable、それはオールオアナッシング(フロー制御の例外を除く)になります。

ほとんどの場合それは問題ではなく、より一般的なインターフェースが必要になります。ただし、反復に対してよりカスタマイズされた制御が必要な場合はIterator、から取得できるが必要になりますIterable


1

ダニエルの答えはいいですね。それを自分の言葉で説明できるか見てみましょう。

そのため、Iterableはイテレータを提供し、要素を1つずつ(next()を使用して)トラバースし、好きなように停止および移動できます。これを行うには、イテレータが要素の位置への内部「ポインタ」を保持する必要があります。ただし、Traversableを使用すると、停止せずにすべての要素を一度にトラバースできます。

Range(1、10)のようなものは、Traversableとして状態として2つの整数のみを持つ必要があります。しかし、IterableとしてのRange(1、10)は、状態に3つの整数を使用する必要があるイテレータを提供します。そのうちの1つはインデックスです。

TraversableはfoldLeft、foldRightも提供することを考えると、そのforeachは既知の固定された順序で要素をトラバースする必要があります。したがって、Traversableのイテレータを実装することが可能です。たとえば、def iterator = toList.iterator

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.