2014-11-23 5 views
0

Целью первого фрагмента кода ниже является определение нового признака для iterables, который предоставляет дополнительный метод для добавления нового элемента перед итерируемым.Получение правильного итератора

Однако при запуске кода во втором фрагменте мы видим, что метод +: возвращает итерабельность, дающую бесконечность 0 s.

Что я делаю неправильно и как я могу получить предполагаемое поведение?

Примечание: я добавил outer val, чтобы убедиться, что получаю правильный итератор при определении методов объекта, возвращаемого +:; Я не знаю, как получить доступ к этому итератору иначе (Iterable2.this.iterator не скомпилировал).

trait Iterable2[A] extends Iterable[A] { 
    val outer :Iterable[A] = this 
    def +:(elem :A) = new Iterable2[A] { 
    override def iterator: Iterator[A] = new Iterator[A] { 
     private[this] var virgin = true 
     override def hasNext: Boolean = virgin || outer.iterator.hasNext 
     override def next(): A = { 
     if (virgin) {virgin = false; elem} 
     else outer.iterator.next() 
     } 
    } 
    } 
} 
val i = new Iterable2[Int] { 
    override def iterator: Iterator[Int] = Iterator(1,2,3) 
} 

for (j <- 0 +: i) { 
    println(j) 
} 
+1

Бросив догадку там: это может быть, что переопределение итератора как опр означает, что он пересчитывает новый итератора каждый раз, таким образом, всегда добавляя новый итератор вида- , 1,2,3, но всегда от 0? –

+1

С стилистической нотой: вам не нужно вводить 'val' для' outer', явная ссылка на внешний объект также может (и, возможно, более элегантно) быть достигнута путем замены строки 'val outer' на' external => '. – misberner

+0

Спасибо, @misberner! Я надеялся, что кто-то прокомментирует, как это сделать должным образом. Я нашел [this] (http://docs.scala-lang.org/tutorials/tour/explicitly-typed-self-references.html) статью о документации Scala, которая вводит синтаксическую конструкцию 'outer =>', хотя для разных целей , Может быть, есть лучшая ссылка? –

ответ

0

Первая ошибка в моем исходном коде является то, что outer.iterator возвращает новый итератор каждый раз, когда он оцененную , как указано @DiegoMartinoia и @Imm.

Однако, также необходимо заменить val outer = this на outer =>, как предложено @misberner.

На данный момент это лишь частичный ответ на мой вопрос, поскольку он не объясняет, почему требуется второе изменение.

Исправленный код черты таким образом:

trait Iterable2[A] extends Iterable[A] { 
    outer :Iterable[A] => 
    def +:(elem :A) = new Iterable2[A] { 
    override def iterator: Iterator[A] = new Iterator[A] { 
     private[this] var virgin = true 
     private[this] val underlyingIterator = outer.iterator 
     override def hasNext: Boolean = virgin || underlyingIterator.hasNext 
     override def next(): A = { 
     if (virgin) {virgin = false; elem} 
     else underlyingIterator.next() 
     } 
    } 
    } 
} 
1

outer.iterator всегда даст вам новый итератор. Вам нужно создать и копить его где-нибудь, а затем использовать этот единственный спрятали один, а не создавать новую каждый раз, когда:

new Iterator[A] { 
    val outerIterator = outer.iterator 
    override def hasNext = ... 
} 
+0

Правда, я об этом не думал. Однако этого недостаточно для создания желаемого поведения. Его нужно сочетать с предложением @ misberner. –