Можно ли расширить итератор значениями, созданными внутри функции?
Да:
fn example<'a>(input: impl Iterator<Item = i32> + 'a) -> impl Iterator<Item = i32> + 'a {
Some(42).into_iter().chain(input).chain(Some(99))
}
fn main() {
for i in example(vec![1, 2, 3].into_iter()) {
println!("{}", i);
}
}
Я ищу способ поворотаonce(head)
в итератор &A
Возьмите ссылку на значение:
iter::once(&head)
Возможно ли заставить [этот конкретный код] работать?
Нет.Компилятор даже скажет вам, что:
error[E0515]: cannot return value referencing local variable `head`
--> src/lib.rs:10:5
|
10 | iter::once(&head).chain(xs.iter()).scan(accum, |accum, x| {
| ^ ----- `head` is borrowed here
| _____|
| |
11 | | *accum += x.0;
12 | | Some(B(*accum))
13 | | })
| |______^ returns a value referencing data owned by the current function
См. Также:
Возможно ли заставить [что-то, близкое к этому коду] работать?
Может быть.Поскольку scan
начинается со значения аккумулятора, вы можете просто использовать его вместо того, чтобы вставлять его в итератор:
fn scan_something<'a>(xs: &'a [A]) -> impl Iterator<Item = B> + 'a {
xs.iter().scan(xs.len(), |accum, x| {
*accum += x.0;
Some(B(*accum))
})
}
Это будет означать, что в полученном итераторе будет на один элемент меньше.Если это приемлемо, зависит от вашего использования.
Более сложное решение состоит в том, чтобы иметь перечисление, которое представляет либо заемную, либо собственную стоимость.Затем вы можете создать итератор этих перечислений из входных данных и локального значения.Владение локальным значением передается возвращаемому итератору:
struct A(usize);
struct B(usize);
use std::iter;
// `A` doesn't implement `Clone`; if it did, use `Cow`
enum OwnedOrBorrowed<'a, T> {
Owned(T),
Borrowed(&'a T),
}
impl<'a, T> std::ops::Deref for OwnedOrBorrowed<'a, T> {
type Target = T;
fn deref(&self) -> &T {
match self {
OwnedOrBorrowed::Owned(t) => t,
OwnedOrBorrowed::Borrowed(t) => t,
}
}
}
fn scan_something<'a>(xs: &'a [A]) -> impl Iterator<Item = B> + 'a {
let accum = 0;
let head = OwnedOrBorrowed::Owned(A(xs.len()));
let borrowed = xs.iter().map(OwnedOrBorrowed::Borrowed);
iter::once(head).chain(borrowed).scan(accum, |accum, x| {
*accum += x.0;
Some(B(*accum))
})
}
Это не бесплатно - каждый вызов закрытия scan
будет выполнять условную логику для проверки, является ли значение владельцем или заимствованным..
См. Также: