返回包含函数拥有数据的数据。

5

我希望有一个DataAllocator,可以返回生命周期为'r的数据,这样我就可以将其传递给something并仍然能够返回在something内分配的值:

use std::marker::PhantomData;

pub struct Data<'a, T>{
    a: &'a [T]
}

impl<'a, T> Data<'a, T> {
    pub fn new() -> Data<'a, T> {
        todo!()
    }
    
    fn iter(&'a self) -> Iter<'a, T> {
        todo!()
    }
}

pub struct Iter<'a, T> {
    _phantom: PhantomData<&'a T>
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<Self::Item> {
        todo!()
    }
}

pub trait DataAllocator<'s, 'r, T> {
    fn allocate(&'s self) -> Box<dyn AsRef<[T]> + 'r>;
}

impl<'s, 'r, T> DataAllocator<'s, 'r, T> for Data<'r, T> {
    fn allocate(&'s self) -> Box<dyn AsRef<[T]> + 'r> {
        todo!()
    }
}

fn do_something<'a, 'b, T>(data_allocator: &'a dyn DataAllocator<'a, 'b, T>) -> Data<'b, T> {
    let buffer = data_allocator.allocate();
    let data = Data{a: (*buffer).as_ref()};
    for e in data.iter(){}
    data
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2a3e0d0cdea86238413af25dddd04e19

error[E0515]: cannot return value referencing local data `*buffer`
  --> src/lib.rs:42:5
   |
40 |     let data = Data{a: (*buffer).as_ref()};
   |                        ------------------ `*buffer` is borrowed here
41 |     for e in data.iter(){}
42 |     data
   |     ^^^^ returns a value referencing data owned by the current function

问题在于如果我尝试迭代 data,它会抱怨我正在尝试返回由 .iter() 函数借用的某些内容。我认为这可能与我说 .iter() 借用了 Data 的生命周期 'b(分配数据的整个生命周期)有关。在这种情况下,我该怎么办?

1
如果你移除迭代,你仍然会得到完全相同的错误。 - Sven Marnach
如果您只对返回切片或 Vec 感兴趣,可以考虑使用 Cow<'r, [T]> 替代 Box<AsRef> - kmdreko
1个回答

4

我认为混淆在于对 dyn AsRef<[T]> + 'r 进行 .as_ref(),返回的是一个与自身相关联的引用,而不是生命周期为 'r 的引用。所以你从 (*buffer).as_ref() 得到的引用是源自于 buffer,而它显然已经超出了作用域。

虽然很难确定你应该如何处理这个问题,因为 todo!() 语句遮蔽了你计划如何解决它。但根据我看到的内容,我可能会期望 allocate() 返回一个 &'r [T]。参见Playground


现在我明白了。你的解决方案的问题在于它只允许我返回引用。如果我想要真正分配一个独立存在的东西怎么办?例如,我可以使用TypedArena来分配一个真正的切片,但我也可能想要使用一个效率低下的分配器来分配一个仅由Vec组成的东西,这个东西是独立存在的。这就是为什么我希望Box包含任何实现AsRef<[T]>的内容,而不仅仅是返回一个切片。你觉得这可能吗? - Rafaelo
总之,我想返回一个实现了 AsRef 的东西的盒子,但这个东西可能是一个切片(短生命周期)或者一个 vec(静态生命周期)。第二种情况是为了当我需要将东西传递给其他线程等情况。 - Rafaelo
你可以实现自己类似于 AsRef 的 trait,就像这样。但我觉得这并不能满足你的意图,因为即使你返回一个拥有所有权的 Vec,它仍然被隐藏在那个 trait 对象后面,并且仍然会像切片一样绑定到 'r 生命周期上。 - kmdreko
是的,但我需要返回 Vec 的时候,编译时必须使用 'r = 'static。我真的不需要在运行时选择它。我喜欢实现自己的 AsRef,但在需要 AsRef 的地方它就不会自动工作,有点无聊 :c - Rafaelo
我正在尝试从您的示例中实现DataRef,用于Vec,但是如果在&self中没有'a,则似乎不可能实现,但是如果我这样做,那么其他东西会出现很多问题。 - Rafaelo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接