我正在尝试编写一个将Arc<[T]>
映射到Iterable
的函数,以便与flat_map
一起使用(也就是说,我想为其他人调用i.flat_map(my_iter)
i: Iterator<Item=Arc<[T]>>
)。
fn my_iter<'a, T>(n: Arc<[T]>) -> slice::Iter<'a, T> {
let t: &'a [T] = &*n.clone();
t.into_iter()
}
上面的函数不起作用,因为n.clone()
生成了Arc<[T]>
类型的拥有值,我可以取消引用[T]
然后借用来获取&[T]
,但是借用的生命周期只持续到函数结束,而'a
生存期将持续到客户端删除返回的迭代器。
如何以客户端获取克隆所有权的方式克隆Arc
,以便仅在客户端完成迭代器之后删除该值(假设没有其他人使用{ {1}})?
这里是源迭代器的一些示例代码:
Arc
如果struct BaseIter<T>(Arc<[T]>);
impl<T> Iterator for BaseIter<T> {
type Item = Arc<[T]>;
fn next(&mut self) -> Option<Self::Item> {
Some(self.0.clone())
}
}
生成数据,而不仅仅是借用数据,我如何实现BaseIter(data).flat_map(my_iter)
(类型为Iterator<&T>
)的结果? (真实的东西比这更复杂,它并不总是相同的结果,但所有权语义是相同的。)
答案 0 :(得分:4)
你不能这样做。请记住,Rust中的生命周期是纯粹的编译时实体,仅用于验证您的代码是否不会意外访问已删除的数据。例如:
fn my_iter<'a, T>(n: Arc<[T]>) -> slice::Iter<'a, T>
这里'a
不会“持续到客户端丢弃返回的迭代器”;这个推理是不正确的。从slice::Iter
的角度来看,它的生命周期参数意味着它指向的切片的生命周期;从my_iter
'a
的角度来看,这只是一个生命周期参数,可以由调用者选择任意。换句话说,slice::Iter
始终与某些具体生命周期的切片相关联,但my_iter
的签名表明它能够返回任意一生。你看到了矛盾吗?
作为旁注,由于生命周期的协方差,您可以从这样的函数返回一片静态切片:
static DATA: &'static [u8] = &[1, 2, 3];
fn get_data<'a>() -> &'a [u8] {
DATA
}
上面的定义是编译的,但它只能运行,因为DATA
存储在程序的静态内存中,并且当程序运行时总是有效;对于Arc<[T]>
,情况并非如此。
Arc<[T]>
表示共享所有权,即Arc<[T]>
内的数据由原始Arc<[T]>
值的所有克隆共同拥有。因此,当Arc
的最后一个克隆超出范围时,它所包含的值将被删除,并释放相应的内存。现在,考虑如果允许编译my_iter()
将会发生什么:
let iter = {
let data: Arc<[i32]> = get_arc_slice();
my_iter(data.clone())
};
iter.map(|x| x+1).collect::<Vec<_>>();
因为在my_iter()
中'a
可以是任意的,并且没有以任何方式链接到Arc<[T]>
(实际上不可能),所以没有什么能阻止编译这些代码 - 用户可能选择'static
生命周期。但是,此处data
的所有克隆都将被删除,并且其中包含的数组将被释放。在块之后使用iter
是不安全的,因为它现在提供对释放的内存的访问。
如何以客户端获取克隆所有权的方式克隆Arc,以便仅在客户端完成迭代器后丢弃该值(假设没有其他人使用Arc)?
因此,如上所述,这是不可能的。只有数据的所有者确定何时应销毁此数据,并且借用的引用(其存在总是由生命周期参数隐含)可能只在数据存在时借用数据,但借用不能影响数据被销毁的时间和方式。为了使借用引用进行编译,它们需要始终只借用这些引用活动时有效的数据。
您可以做的是重新考虑您的架构。很难说如果不查看完整的代码可以做些什么,但是在这个特定的例子中,你可以,例如,首先将迭代器收集到一个向量中,然后迭代向量:
let items: Vec<_> = your_iter.collect();
items.iter().flat_map(my_iter)
请注意,现在my_iter()
确实应该接受&Arc<[T]>
,正如FrancisGagné所建议的那样;这样,输出迭代器的生命周期将与输入引用的生命周期相关联,并且一切都应该正常工作,因为现在可以保证Arc
被稳定地存储在向量中,以便稍后在迭代。
答案 1 :(得分:2)
通过传递Arc<[T]>
值,无法完成这项工作。您需要从对Arc<[T]>
的引用开始,才能构建有效的slice::Iter
。
fn my_iter<'a, T>(n: &'a Arc<[T]>) -> slice::Iter<'a, T> {
n.into_iter()
}
或者,如果我们忽视了一生:
fn my_iter<T>(n: &Arc<[T]>) -> slice::Iter<T> {
n.into_iter()
}
答案 2 :(得分:0)
您需要使用另一个迭代器作为函数my_iter
的返回类型。 slice::Iter<'a, T>
具有关联的类型Item = &'a T
。您需要一个关联类型为Item = T
的迭代器。像vec::IntoIter<T>
这样的东西。您可以自己实现这样的迭代器:
use std::sync::Arc;
struct BaseIter<T>(Arc<[T]>);
impl<T> Iterator for BaseIter<T> {
type Item = Arc<[T]>;
fn next(&mut self) -> Option<Self::Item> {
Some(self.0.clone())
}
}
struct ArcIntoIter<T>(usize, Arc<[T]>);
impl<T:Clone> Iterator for ArcIntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.0 < self.1.len(){
let i = self.0;
self.0+=1;
Some(self.1[i].clone())
}else{
None
}
}
}
fn my_iter<T>(n: Arc<[T]>) -> ArcIntoIter<T> {
ArcIntoIter(0, n)
}
fn main() {
let data = Arc::new(["A","B","C"]);
println!("{:?}", BaseIter(data).take(3).flat_map(my_iter).collect::<String>());
//output:"ABCABCABC"
}