具有更长生命周期的返回对象的可变借用
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_subview
和 into_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_mut
、split_at_mut
、chunks_mut
等切片上的可变方法中获取灵感,这些方法经过精心设计,可同时获取多个可变 elements/sub-slices。
你可以使用std::mem::transmute
强制生命周期成为你想要的(警告:transmute
非常unsafe
并且很容易被错误地使用),然而,你自己却背负着维护上述引用保证的负担。然后 subview() -> MutView<'s>
函数应标记为 unsafe
,并带有范围互斥的安全要求。我不建议这样做,除非在您返回多个可变引用并检查它们不重叠的特殊情况下。
我必须看看你希望设计什么样的 API 才能提供更好的建议。
我目前正在尝试将可变 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_subview
和 into_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
andinto_slice
method that consumes self.
我看到的主要选项,您需要保证的关键部分是排他性,消耗 self
会将其从等式中删除。您还可以从 split_mut
、split_at_mut
、chunks_mut
等切片上的可变方法中获取灵感,这些方法经过精心设计,可同时获取多个可变 elements/sub-slices。
你可以使用std::mem::transmute
强制生命周期成为你想要的(警告:transmute
非常unsafe
并且很容易被错误地使用),然而,你自己却背负着维护上述引用保证的负担。然后 subview() -> MutView<'s>
函数应标记为 unsafe
,并带有范围互斥的安全要求。我不建议这样做,除非在您返回多个可变引用并检查它们不重叠的特殊情况下。
我必须看看你希望设计什么样的 API 才能提供更好的建议。