所以我有一个函数,看起来像这样
fn foo() {
let items = vec![0.2, 1.5, 0.22, 0.8, 0.7, 2.1];
let mut groups: HashMap<u32, String> = HashMap::new();
let mut group = |idx: f32| -> &mut String {
let rounded = (idx / 0.2).floor() as u32;
groups
.entry(rounded)
.or_insert_with(|| format!("{}:", rounded))
};
for item in items.iter() {
group(*item).push_str(&format!(" {}", item))
}
}
此代码不编译,出现以下错误:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:9:9
|
5 | let mut groups: HashMap<u32, String> = HashMap::new();
| ---------- variable defined here
6 |
7 | let mut group = |idx: f32| -> &mut String {
| - inferred to be a `FnMut` closure
8 | let rounded = (idx / 0.2).floor() as u32;
9 | groups
| ^-----
| |
| _________variable captured here
| |
10 | | .entry(rounded)
11 | | .or_insert_with(|| format!("{}:", rounded))
| |_______________________________________________________^ returns a reference to a captured variable which escapes the closure body
|
= 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
Edit
正如@Sven Marnach所指出的,这里的问题是,我可以为同一个对象创建两个可变引用:
fn foo() {
// ...
let ok = groups(0.1);
let problem = groups(0.1);
}
Original (incorrect)
我认为Rust告诉我,闭包
group
可变地捕获变量groups
,然后返回对groups
拥有的对象的引用.所以这里的危险在于,下面的代码将返回一个悬空指针(因为groups
在foo
完成后超出范围时会被删除).fn foo() -> &String { /* ... */ return groups(0.1); }
那么,有没有办法像这样从捕获的可变HashMap
返回一个引用?