我有一系列Boxed值的迭代器。我想将这个迭代器映射到一个对盒装值的可变引用。
以下简化示例显示了如何为不可变引用实现此功能。这个例子编译得很好。
let indices = [0usize, 1usize, 2usize];
let vec = vec![Box::new(1.0), Box::new(2.0), Box::new(3.0)];
let i = indices.iter().map(|index| vec[*index].deref()).map(|x| *x + 1.0);
但是,对于可变引用,如下例所示,编译器会产生错误。
let indices = [0usize, 1usize, 2usize];
let mut vec = vec![Box::new(1.0), Box::new(2.0), Box::new(3.0)];
let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0);
编译器错误如下:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src\port_graph/mod.rs:200:40
|
200 | let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0);
| ^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime as defined on the body at 200:39...
--> src\port_graph/mod.rs:200:40
|
200 | let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0);
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that closure can access `vec`
--> src\port_graph/mod.rs:200:40
|
200 | let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0);
| ^^^
note: but, the lifetime must be valid for the scope of call-site for function at 200:39...
--> src\port_graph/mod.rs:200:40
|
200 | let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0);
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that return value is valid for the call
--> src\port_graph/mod.rs:200:32
|
200 | let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
如何解决这个问题?
编辑:对于一个简单的向量,可以简单地执行以下操作。但是,上面的例子是我想要迭代图形中的节点子集(petgraph crate)的情况的简化,我不想自己使用图形。
let mut vec = vec![Box::new(1.0), Box::new(2.0), Box::new(3.0)];
let i = vec.iter_mut().map(|boxed| boxed.deref_mut()).map(|x| *x = *x + 1.0);
答案 0 :(得分:4)
不可变引用和可引用引用之间存在巨大差异。借款的核心原则是:
别名XOR可变性
Rust语言保证如果你有一个可变引用,就没有其他引用可以对同一个对象进行别名。
在您的情况下,我们不是再次映射,而是收集地址:
size()
我们得到了向量中元素的地址列表。
仅这些地址不同的原因是因为索引不同。如果我们偷偷摸摸,并将std::string
初始化为let c: Vec<_> = indices.iter().map(|index| vec[*index].deref())
.map(|x| x as *const _ as usize)
.collect();
println!("{:?}", c);
,那么我们会遇到别名。
如果我们可以根据运行时属性获得别名,那么我们也不应该变得可变;因此类型系统强制执行此操作。
如何执行?
关闭借用indices
。
[0, 1, 2, 1]
,关闭借用vec
deref
,关闭借用&Vec
你可以亲自见证第一个:
deref_mut
将失败并注意到该向量已被闭包不可靠地借用。
第二个是逻辑扩展名:
&mut Vec
在论证中使用let i = indices.iter().map(|index| vec[*index].deref())
.map(|x| x as *const _ as usize);
vec[0] = Box::new(3.0);
deref_mut
需要&mut self
参数,因此,每次调用闭包时,它都会访问IndexMut
。因此,每次调用闭包时,NOTHING必须为此&mut self
设置别名,因此没有引用必须在闭包之外泄漏。
这是如何实现的?
通过收紧在闭包中访问的引用的生命周期:每次调用闭包时,都会得到&mut Vec
引用,其中&mut Vec
是闭包体的范围而且没有了。
(这也与重新生成和&'scope mut Vec
不是'scope
的事实有关:因为您无法移交内部存储的&mut T
的副本,因为它&#39 ;而不是Copy
,你被移交了重新借用&mut T
,它有一个新的生命周期。)
那么解决方案是什么?
直接在您有权访问Copy
的闭包中执行任何和所有计算。在这个闭包中,毕竟你有可变的访问权。
&mut *vec
正确显示Vec
。