冲突的生命周期——埋入的内容无法比容器长寿
Conflicting Lifetimes - Burrowed Content is Unable to Outlive Container
我正在尝试为我的一个结构实施 Iterator
:
pub struct Node {
pub val: Vec<usize>,
}
pub struct NodeIter<'a, 'b> {
val: &'a Vec<usize>,
env: &'b mut Env,
index: usize,
}
impl<'a, 'b> Iterator for NodeIter<'a, 'b> {
type Item = &'b mut Obj;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.val.len() {
return Some(self.env.get_obj_at_mut(self.val[self.index]))
}
self.index += 1;
None
}
}
编译时出现以下错误:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src\core\nodes.rs:20:23
|
20 | Some(self.env.get_obj_at_mut(self.val[self.index]))
| ^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src\core\nodes.rs:19:13
|
19 | fn next(&mut self) -> Option<&'a mut Obj> {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src\core\nodes.rs:20:14
|
20 | Some(self.env.get_obj_at_mut(self.val[self.index]))
| ^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src\core\nodes.rs:16:6
|
16 | impl<'a> Iterator for NodeIter<'a> {
| ^^
note: ...so that the types are compatible
--> src\core\nodes.rs:20:9
|
20 | Some(self.env.get_obj_at_mut(self.val[self.index]))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Option<&'a mut Obj>`
found `Option<&mut Obj>`
我理解的问题是来自 get_obj_at_mut
的 &mut Obj
(returns 一个生命周期为 'b
的 &mut Obj,与 env
) 可能会比 &mut self
长寿,并在其位置留下一个空引用。问题是 env
受可变引用的约束,可能持续超过 NodeIter
所以我尝试了两种选择:
'b: 'c
:
impl<'a, 'b> NodeIter<'a, 'b> {
fn next_impl<'c>(&'c mut self) -> Option<&'b mut Obj> where 'b: 'c {
if self.index < self.val.len() {
return Some(self.env.get_obj_at_mut(self.val[self.index]))
}
self.index += 1;
None
}
}
这失败了,说明 'b
不能比 'c
长寿
'c: 'b
impl<'a, 'b> NodeIter<'a, 'b> {
fn next_impl<'c>(&'c mut self) -> Option<&'b mut Obj> where 'c: 'b {
if self.index < self.val.len() {
return Some(self.env.get_obj_at_mut(self.val[self.index]))
}
self.index += 1;
None
}
}
这允许 next-impl
成功编译,但由于生命周期限制
无法从 next
调用它
我知道这可能与关于 Rust 生命周期的其他问题类似,但我一直无法弄清楚为什么 'b
不能比 'c
更普遍地实现 Iterator
我对 Rust 还是个新手,所以非常感谢任何帮助
编辑
pub fn get_obj_at_mut(&mut self, index: usize) -> &mut Obj {
&mut self.symbols[index]
}
这是 Env
的 impl
块,其中 symbols
是 Obj
的 Vec
如果 val
包含重复索引,您尝试的实现将使将两个可变借用保持到相同的 Obj
值成为可能。考虑一下如果 val
包含重复索引并且此代码的用户 .collect()
将迭代器编辑为 Vec
会发生什么!这种情况是 Rust 的内存安全规则不允许的,这就是 next()
实现编译失败的最终原因。
事实上,任何你能想出的实现都会遇到这个基本问题:没有什么能阻止Iterator::next()
在你仍然持有可变引用 return 来自先前的调用,并且该语言不能保证迭代器生成的所有可变引用都将别名为不同的值。
那么切片上的 iter_mut()
是如何工作的呢?简单:they use unsafe code。 unsafe
是你告诉编译器你自己完成了工作以证明你正在做的事情没有违反 Rust 的任何安全规则的地方,因此它允许你做一些你不能做的额外事情通常。
如果你想在不使用不安全代码的情况下做到这一点,你将不得不交换迭代,这样你就可以调用 iter_mut()
对你的 Env
内部的任何集合进行过滤根据 Node
中的索引向下。这显然对性能有影响,而且很可能以不同的顺序迭代。
这是一个完整的示例,展示了它是如何工作的,其中包含 Env
:
的占位符方法
pub struct Env;
pub struct Obj;
impl Env {
#[allow(unreachable_code)]
pub fn iter_mut(&mut self) -> impl Iterator<Item=&mut Obj> {
todo!();
std::iter::empty()
}
pub fn get_obj_at_mut(&mut self, _: usize) -> &mut Obj {
todo!();
}
}
pub struct Node {
pub val: Vec<usize>,
}
impl Node {
pub fn iter_mut<'a>(&'a self, env: &'a mut Env)
-> impl Iterator<Item=&'a mut Obj>
{
env.iter_mut()
.enumerate()
.filter_map(move |(index, v)|
if self.val.contains(&index) { Some(v) } else { None }
)
}
}
如果此方法的性能和顺序影响不可接受,那么不安全代码是您唯一的选择。特别是,您必须验证 val
不包含重复索引,否则您将违反 Rust 的规则,即对任何给定值最多只能有一个可用的可变引用。
如果您在构造 NodeIter
值之前已经验证了这一点,那么您可以使用不安全代码来说服 Rust,您在这里所做的是可以的。请注意,在这段代码中,我还修复了索引永远不会递增的错误,因为你 return 早了。
impl<'a, 'b> Iterator for NodeIter<'a, 'b> {
type Item = &'b mut Obj;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.val.len() {
let obj = self.env.get_obj_at_mut(self.val[self.index]);
self.index += 1;
// SAFETY: We already verified that self.val contains
// no duplicate indices, and nobody can modify it while
// we hold a reference to it, so it's not possible for
// this iterator to produce two references to the same
// value.
// Convert to a pointer then back, which makes Rust
// blind to the lifetime of the original reference.
Some(unsafe { &mut *(obj as *mut _) })
} else {
None
}
}
}
我正在尝试为我的一个结构实施 Iterator
:
pub struct Node {
pub val: Vec<usize>,
}
pub struct NodeIter<'a, 'b> {
val: &'a Vec<usize>,
env: &'b mut Env,
index: usize,
}
impl<'a, 'b> Iterator for NodeIter<'a, 'b> {
type Item = &'b mut Obj;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.val.len() {
return Some(self.env.get_obj_at_mut(self.val[self.index]))
}
self.index += 1;
None
}
}
编译时出现以下错误:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src\core\nodes.rs:20:23
|
20 | Some(self.env.get_obj_at_mut(self.val[self.index]))
| ^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src\core\nodes.rs:19:13
|
19 | fn next(&mut self) -> Option<&'a mut Obj> {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src\core\nodes.rs:20:14
|
20 | Some(self.env.get_obj_at_mut(self.val[self.index]))
| ^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src\core\nodes.rs:16:6
|
16 | impl<'a> Iterator for NodeIter<'a> {
| ^^
note: ...so that the types are compatible
--> src\core\nodes.rs:20:9
|
20 | Some(self.env.get_obj_at_mut(self.val[self.index]))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Option<&'a mut Obj>`
found `Option<&mut Obj>`
我理解的问题是来自 get_obj_at_mut
的 &mut Obj
(returns 一个生命周期为 'b
的 &mut Obj,与 env
) 可能会比 &mut self
长寿,并在其位置留下一个空引用。问题是 env
受可变引用的约束,可能持续超过 NodeIter
所以我尝试了两种选择:
'b: 'c
:
impl<'a, 'b> NodeIter<'a, 'b> {
fn next_impl<'c>(&'c mut self) -> Option<&'b mut Obj> where 'b: 'c {
if self.index < self.val.len() {
return Some(self.env.get_obj_at_mut(self.val[self.index]))
}
self.index += 1;
None
}
}
这失败了,说明 'b
不能比 'c
'c: 'b
impl<'a, 'b> NodeIter<'a, 'b> {
fn next_impl<'c>(&'c mut self) -> Option<&'b mut Obj> where 'c: 'b {
if self.index < self.val.len() {
return Some(self.env.get_obj_at_mut(self.val[self.index]))
}
self.index += 1;
None
}
}
这允许 next-impl
成功编译,但由于生命周期限制
next
调用它
我知道这可能与关于 Rust 生命周期的其他问题类似,但我一直无法弄清楚为什么 'b
不能比 'c
更普遍地实现 Iterator
我对 Rust 还是个新手,所以非常感谢任何帮助
编辑
pub fn get_obj_at_mut(&mut self, index: usize) -> &mut Obj {
&mut self.symbols[index]
}
这是 Env
的 impl
块,其中 symbols
是 Obj
Vec
如果 val
包含重复索引,您尝试的实现将使将两个可变借用保持到相同的 Obj
值成为可能。考虑一下如果 val
包含重复索引并且此代码的用户 .collect()
将迭代器编辑为 Vec
会发生什么!这种情况是 Rust 的内存安全规则不允许的,这就是 next()
实现编译失败的最终原因。
事实上,任何你能想出的实现都会遇到这个基本问题:没有什么能阻止Iterator::next()
在你仍然持有可变引用 return 来自先前的调用,并且该语言不能保证迭代器生成的所有可变引用都将别名为不同的值。
那么切片上的 iter_mut()
是如何工作的呢?简单:they use unsafe code。 unsafe
是你告诉编译器你自己完成了工作以证明你正在做的事情没有违反 Rust 的任何安全规则的地方,因此它允许你做一些你不能做的额外事情通常。
如果你想在不使用不安全代码的情况下做到这一点,你将不得不交换迭代,这样你就可以调用 iter_mut()
对你的 Env
内部的任何集合进行过滤根据 Node
中的索引向下。这显然对性能有影响,而且很可能以不同的顺序迭代。
这是一个完整的示例,展示了它是如何工作的,其中包含 Env
:
pub struct Env;
pub struct Obj;
impl Env {
#[allow(unreachable_code)]
pub fn iter_mut(&mut self) -> impl Iterator<Item=&mut Obj> {
todo!();
std::iter::empty()
}
pub fn get_obj_at_mut(&mut self, _: usize) -> &mut Obj {
todo!();
}
}
pub struct Node {
pub val: Vec<usize>,
}
impl Node {
pub fn iter_mut<'a>(&'a self, env: &'a mut Env)
-> impl Iterator<Item=&'a mut Obj>
{
env.iter_mut()
.enumerate()
.filter_map(move |(index, v)|
if self.val.contains(&index) { Some(v) } else { None }
)
}
}
如果此方法的性能和顺序影响不可接受,那么不安全代码是您唯一的选择。特别是,您必须验证 val
不包含重复索引,否则您将违反 Rust 的规则,即对任何给定值最多只能有一个可用的可变引用。
如果您在构造 NodeIter
值之前已经验证了这一点,那么您可以使用不安全代码来说服 Rust,您在这里所做的是可以的。请注意,在这段代码中,我还修复了索引永远不会递增的错误,因为你 return 早了。
impl<'a, 'b> Iterator for NodeIter<'a, 'b> {
type Item = &'b mut Obj;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.val.len() {
let obj = self.env.get_obj_at_mut(self.val[self.index]);
self.index += 1;
// SAFETY: We already verified that self.val contains
// no duplicate indices, and nobody can modify it while
// we hold a reference to it, so it's not possible for
// this iterator to produce two references to the same
// value.
// Convert to a pointer then back, which makes Rust
// blind to the lifetime of the original reference.
Some(unsafe { &mut *(obj as *mut _) })
} else {
None
}
}
}