我想在一个结构体中可变地覆盖两个元素,但我得到了一个错误。下面是简化的代码:
use std::collections::HashMap;
struct Attr {
value1: usize,
value2: Vec<usize>
}
impl Default for Attr {
fn default() -> Self {
Self {
value1: 100,
value2: vec![1;1000],
}
}
}
struct Data {
inner: Vec<usize>, //A complex structure in real code
attrs: HashMap<usize, Attr>,
}
fn iter_data(d: &mut Data) -> impl Iterator<Item = (usize, &mut Attr)> {
d.inner.iter().map(|x| (*x, d.attrs.get_mut(x).unwrap()))
}
fn main() {
let mut data = Data {
inner: Vec::new(),
attrs: HashMap::new()
};
for i in 1..100 {
data.inner.push(i);
data.attrs.insert(i, Default::default());
}
for (k, v) in iter_data(&mut data){ // mutably iterate data
}
}
字符串
这是一个错误:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:25:28
|
24 | fn iter_data(d: &mut Data) -> impl Iterator<Item = (usize, &mut Attr)> {
| - variable defined here
25 | d.inner.iter().map(|x| (*x, d.attrs.get_mut(x).unwrap()))
| - ^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | | |
| | | variable captured here
| | returns a reference to a captured variable which escapes the closure body
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
型
我想知道如何避免这个错误?我只是想将Data
中的每个元素都重新编译,并修改每个元素的attrs
。我知道我可以直接用(key, value)
重新编译attrs
,但在真实的代码中存在一些问题。
1条答案
按热度按时间63lcw9qa1#
函数
fn iter_data(d: &mut Data) -> impl Iterator<Item = (usize, &mut Attr)>
不能以这种方式工作,除了Rust中的实际实现可以防止这个问题之外,考虑inner: Vec<usize>
包含值vec![0, 0]
的情况,我会调用字符串
iter_data()
目前的编写方式是bar
现在必须包含两个&mut
--对同一个Attr
(vec![(0, &mut Attr), (0, &mut Attr)]
)的引用,这是不可能的,编译器也无法静态地证明这不会发生。有两种方法可以解决这个问题:
RefCell
可可变地借用data
。这允许闭包不可变地捕获data
,将FnMut
降级为Fn
。这也会导致在运行时将上面的精心设计的示例转换为panic!()
,而Iterator
实际上是collect()
。或者通过任何其它方式,第二个&mut
到同一个Attr
即将出现。iter_data()
,使其接受一个闭包,该闭包对每个项都执行。这允许您根本不返回对调用方的引用,这就减轻了编译器证明这些引用不会转义的需要。我推荐第二种方法,作为一个一般的经验法则:在处理
&mut
引用时,通常更容易让代码到数据,而不是让数据到代码。