将装箱值映射到Rust中的可变取消引用值

时间:2017-03-01 14:47:23

标签: iterator rust lifetime

我有一系列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);

1 个答案:

答案 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