我有一个program对其参数执行scan
操作:
struct A(usize);
struct B(usize);
fn scan_something<'a>(xs: &'a [A]) -> impl Iterator<Item = B> + 'a {
let accum = 0;
xs.iter().scan(accum, |accum, x| {
*accum += x.0;
Some(B(*accum))
})
}
我想用在函数内部生成的一些值扩展迭代器:
fn scan_something<'a>(xs: &'a [A]) -> impl Iterator<Item = B> + 'a {
let accum = 0;
let head: A = A(xs.len());
use std::iter::once;
once(head).chain(xs.iter()).scan(accum, |accum, x| {
*accum += x.0;
Some(B(*accum))
})
}
这不会编译,因为once(head)
是A
的迭代器,而xs.iter()
是&A
的迭代器。
我可以为Clone
实现A
并将.cloned()
放在xs.iter()
之后进行修复,但是我不想克隆整个xs
,因为可能会很长,并且实际程序中的A
克隆起来并不便宜。
我正在寻找一种将once(head)
转换为&A
的迭代器的方法,但是找不到任何方法。
能否使其正常工作?
答案 0 :(得分:2)
我可以使用在函数内部创建的值扩展迭代器吗?
是:
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
闭包的每次调用都会执行条件逻辑,以测试该值是否已拥有或借用。
另请参阅:
答案 1 :(得分:0)
fn main() {
let a: &[A] = &[A(1), A(2), A(3)];
let b: &[A] = &[A(a.len())];
for s in scan_something(b, a) {
println!("{:?}", s);
}
}
fn scan_something<'a>(xs1: &'a [A], xs: &'a [A]) -> impl Iterator<Item = B> + 'a {
let iter3 = xs1.iter().chain(xs.iter());
let accum = 0;
iter3.scan(accum, |accum, x| {
*accum += x.0;
Some(B(*accum))
})
}
#[derive(Debug)]
struct A(usize);
#[derive(Debug)]
struct B(usize);
输出:
B(3)
B(4)
B(6)
B(9)