Поскольку ему требуется некоторый способ сообщить вызывающей стороне, что ничего не осталось для вывода.
fn main() {
let mut it = vec![1, 2, 3].into_iter();
assert_eq!(it.next(), Some(1));
assert_eq!(it.next(), Some(2));
assert_eq!(it.next(), Some(3));
assert_eq!(it.next(), None); // End of iterator.
}
Что касается гипотетического has_next
, это может усложнить некоторые конструкции итераторов, посколькуэто требует, чтобы итератор знал , есть ли другой элемент.Это может потребовать, чтобы итератор вычислил следующий элемент, а затем сохранил его где-нибудь.Также можно забыть вызвать has_next
или вызвать его, но проигнорировать результат.
С next
, возвращающим Option
, все это не является проблемой;итератор может вычислить следующий элемент и вернуть его, в то время как вызывающая сторона не может забыть убедиться, что возвращаемое значение действительно содержит что-то.
Одна вещь, которая делает , а не , позволяет вам сделать"заглядывать" в итератор, чтобы увидеть, есть ли что-то еще, а затем изменить логику на основе этого ответа, без , фактически потребляющего следующий элемент.Однако для этого и нужен комбинатор peekable
, который дает вам то, что составляет традиционный has_next
: peek().is_some()
.
Что касается вашей обеспокоенности по поводу производительности: я никогда не видел ничего, что могло бы предложитьлюбой штраф.Все, что правильно использует итератор , имеет , чтобы проверить, достигнут ли он конца.Что касается пространства, итератору Rust не нужно кэшировать следующий элемент, поэтому он, вероятно, будет того же размера или меньше, чем итератор для языка, который использует has_next
.
Наконец, какотмечается в комментариях, Option
не выделяется куча.None
эквивалентно false
, за которым следует неинициализированное пространство (поскольку в нем ничего нет), а Some(v)
эквивалентно true
, за которым следует v
.