具有更长生命周期的返回对象的可变借用

Mutable borrow with returned object of longer lifetime

我目前正在尝试将可变 slice/view 实现到缓冲区中,该缓冲区支持安全地获取子切片以进行内存中消息遍历。一个最小的例子是

struct MutView<'s> {
    data: &'s mut [u8]
}

impl<'s> MutView<'s> {
    pub fn new(data: &'s mut [u8]) -> Self {
        MutView { data }
    }
    pub fn subview<'a>(&'a mut self, start: usize, end: usize) -> MutView<'a> {
        MutView::new(&mut self.data[start..end])
    }
    pub fn get<'a>(&'a mut self) -> &'a mut [u8] {
        self.data
    }
}

但是这个设计有一个问题,如果我有一个 MutView<'s> 是在一个函数中本地创建的,并且 's 比函数的范围长(比如 's = ' static) 我无法从函数返回子视图。像

fn get_subview(data: &'s mut [u8]) -> MutView<'s> {
    MutView::new(data).subview(0, 5)
}

给出一个编译错误,因为 MutView::new(data) 是一个局部临时变量,所以显然 subview() 返回的 MutView<'a> 不能从函数返回。

正在将 subview() 的签名更改为

pub fn subview<'a>(&'a mut self, start: usize, end: usize) -> MutView<'s> {
    MutView::new(&mut self.data[start..end])
}

不可能,因为借用检查器抱怨返回对象的生命周期必须长于 &'a mut self 的生命周期。

我看到的问题是,借用检查器被设置为处理 subview() 正在返回属于 &'a mut self 的数据的情况,而在这种情况下,我正在返回一些底层拥有的数据超过生命周期 'a 的缓冲区,因此出于安全原因,我仍然想在返回对象的生命周期内对 &'a mut self 进行可变借用,同时还允许在不缩短生命周期的情况下删除 &'a mut self返回的子视图。

我看到的唯一选择是添加一个使用 self 的 into_subviewinto_slice 方法。然而,对于我的具体情况,我正在生成 get_/set_ 方法来读取具有给定模式的消息,这意味着我在消息正文中的每个字段都有 get/set 方法,并且添加额外的 into_* 方法意味着很多额外的代码generate/compile,以及额外的使用复杂性。因此,我想尽可能避免这种情况。

目前在 Rust 中有处理这种依赖关系的好方法吗?

subview 返回 MutView<'s> 是不合理的。

它将允许用户多次调用 subview 并产生可能重叠的范围,这将违反 Rust 的引用保证,即可变引用是排他的。这可以通过不可变引用轻松完成,因为它们可以共享,但对可变引用有更严格的要求。出于这个原因,从 self 派生的可变引用必须 将它们的生命周期绑定到 self 以便在可变借用仍然存在时“锁定”对它的访问正在使用。编译器通过告诉您 &mut self.data[..]&'a mut [u8] 而不是 &'s mut [u8].

来强制执行

The only option I see is to add an into_subview and into_slice method that consumes self.

我看到的主要选项,您需要保证的关键部分是排他性,消耗 self 会将其从等式中删除。您还可以从 split_mutsplit_at_mutchunks_mut 等切片上的可变方法中获取灵感,这些方法经过精心设计,可同时获取多个可变 elements/sub-slices。

可以使用std::mem::transmute强制生命周期成为你想要的(警告:transmute非常unsafe 并且很容易被错误地使用),然而,你自己却背负着维护上述引用保证的负担。然后 subview() -> MutView<'s> 函数应标记为 unsafe,并带有范围互斥的安全要求。我不建议这样做,除非在您返回多个可变引用并检查它们不重叠的特殊情况下。

我必须看看你希望设计什么样的 API 才能提供更好的建议。