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

pfr*_*erd 6 rust borrow-checker

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

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

给出编译错误,因为MutView::new(data)它是本地临时的,所以显然不能从函数返回MutView<'a>subview()

将签名更改subview()

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

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

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

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

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

kmd*_*eko 3

返回MutView<'s>fromsubview是不健全的。

subview它将允许用户多次调用并产生可能重叠的范围,这将违反 Rust 的可变引用独占的​​引用保证。这可以通过不可变引用轻松完成,因为它们可以共享,但对于可变引用有更严格的要求。因此,派生自 的可变引用self 必须绑定其生命周期,self以便在可变借用仍在使用时“锁定”对其的访问。编译器通过告诉您&mut self.data[..]is&'a mut [u8]而不是 来强制执行这一点&'s mut [u8]

我看到的唯一选择是添加一个消耗 self 的into_subviewand方法。into_slice

我看到的主要选择是,您需要保证的关键部分是排他性,而消费self会将其从等式中删除。split_mut您还可以从、split_at_mut、等切片上的可变方法中获取灵感,chunks_mut这些方法经过精心设计,可同时获取多个可变元素/子切片。

可以用来std::mem::transmute强制生命周期成为您想要的(警告:transmute非常unsafe容易错误使用),但是,您自己将承担起维护上述引用保证的责任。然后,该subview() -> MutView<'s>功能应标unsafe有范围排他性的安全要求。我不建议这样做,除非在特殊情况下,您返回多个可变引用并检查它们是否不重叠。

我必须确切地了解您希望设计哪种 API 才能提供更好的建议。