
www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1705r0.html
Size: a a a







Read. Подразумевается, что тип, реализующий BufRead, имеет некоторый внутренний буфер, доступ к которому можно получить при помощи fill_buf. Наличие этого внутреннего буфера позволяет реализовать некоторые операции, которые затруднительно реализовывать непосредственно поверх Read, например, read_until.BufRead — это lines, который возвращает итератор строк. Но что именно возвращает этот итератор? Он возвращает Result<String, std::io::Error>. То есть каждый вызов Iterator::next выделяет память в куче под строку. Как-то не zero cost. В конце концов, у типа, реализующего BufRead, есть некий внутренний буфер, так почему нельзя возвращать ссылку на него? Давайте посмотрим внимательнее на типы.Iterator::next имеет следующую сигнатуру:fn next(&mut self) -> Option<Self::Item>;Обратите внимание: несмотря на то, что в
next неявно входит лайфтайм, этот лайфтайм отсутствует в возвращаемом типе! Это означает, что значение, возвращаемое next, может быть, и не владеющее, но оно по крайне мере точно ничего не заимствует из self. А как должен выглядеть гипотетический next у нашего итератора, который возвращает ссылку на внутренний буфер?fn next<'a>(&'a mut self) -> Option<&'a str>;(Я сейчас намеренно опускаю вопрос об ошибках, потому что это не главное в том, что я хочу донести). Чем эта сигнатура кардинально отличается от
Iterator::next? А тем, что (я даже специально расписал лайфтаймы, чтобы это было видно более ясно) возвращаемое значение заимствует self! Таким образом, даже не смотря на то, что технически мы можем написать этот метод, он не подходит под сигнатуру Iterator::next, а значит, мы не можем использовать все эти полезные итераторные комбинаторы.trait AnotherIterator {
    type Item<'a>; // обратите внимание: тип параметризован
    fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
    // комбинаторы поверх next
}
Новая версия итератора позволяет явно выразить тот факт, что мы не можем вызвать next два раза подряд, сохранив оба результата. Да, нам придётся реализовать комбинаторы заново, но этот будут общие методы, а не функции под конкретный тип, которые плохо композируются друг с другом.trait OneMoreiterator<'a> {
    type Item;
    fn next(&'a mut self) -> Option<&'a Self::Item>;
}
Можно. Но это решение обладает рядом недостатков. Первое: его неудобно использовать на практике. Так как нужный нам лайфтайм 'a, скорее всего, будет локальным, а не обобщённым параметром, нам придётся использовать HRTB и писать что-то вродеfn do_stuff<I>(iter: I)Во-вторых — и это уже куда как более сильное ограничение — данное определение позволяет возвращать из
where
I: for<'a> OneMoreIterator<'a>,
{
//...
}
next лишь ссылку на Item, а не произвольный тип, параметризованный лайфтаймом (скажем, я могу себе представить тип, реализующий AnotherIterator и возвращающий MutexGuard). В качестве примера, демонстрирующего оба недостатка, можно назвать WindowsMut, несуществующий пока аналог Windows, возвращающий перекрывающиеся мутабельные подслайсы исходного слайса.









