[英]Rust lifetime issue with closures within same global scope
這是我的代碼中問題的最小表示:
use std::collections::HashMap;
fn main() {
let mut map : HashMap<String, String> = HashMap::new();
map.insert(String::from("a"), String::from("first"));
map.insert(String::from("b"), String::from("second"));
let mut funcs: Vec<Box<dyn FnMut(String) -> ()>> = Vec::new();
for (key, val) in map {
funcs.push(Box::new(|v| {
println!("{} : {} : {}",key,val,v);
}))
}
for mut func in funcs {
func(String::from("c"));
}
}
錯誤:(與val
相同):
`key` does not live long enough
values in a scope are dropped in the opposite order they are defined rustcE0597
main.rs(12, 5): `key` dropped here while still borrowed
main.rs(9, 29): value captured here
main.rs(17, 1): borrow might be used here, when `funcs` is dropped and runs the
`Drop` code for type `Vec`
這是我真實生活用例的極簡主義表示——我正在使用一個庫,它需要我為它提供一堆閉包以便稍后組合執行。 我首先構建一個 HashMap,然后遍歷它以創建 FnMut 列表(在這個最小示例中,Fn 也可以)
我得到的錯誤的一般想法是我正在創建具有臨時生命周期的key
(和val
),該生命周期在每個循環結束時結束,並且閉包具有“延遲”執行,他們將在其中訪問此數據,而不會不再存在 - 但我不知道如何修復它。 我嘗試map.into_iter()
, map.drain()
(不使用引用),用Rc
包裝數據 - 無濟於事。 這里的正確解決方案是什么?
由於構建 map 是一個有點復雜的過程,如果可能的話,我仍然希望在關閉之前構建它。
編輯1:
@Masklinn 在閉包前添加move
的解決方案在這里確實有效,但它在我的真實代碼中產生了其他問題
Vec<MyStruct>
,它不可復制,因此無法移動。 我想我可以通過實現復制特征來解決它(我的結構足夠小,基本上是一堆選項)use of moved value
錯誤:如何處理這種情況? EDIT2:使用move
時第二個問題的說明:
fn main() {
let mut map : HashMap<String, Vec<String>> = HashMap::new();
map.insert(String::from("a"), Vec::from([String::from("first")]));
map.insert(String::from("b"), Vec::from([String::from("first")]));
let map2 : HashMap<String, Vec<String>> = HashMap::new();
let mut funcs: Vec<Box<dyn FnMut(String) -> ()>> = Vec::new();
for (key, val) in map {
funcs.push(Box::new(move |v| {
println!("{} : {:?} : {}, {}",key,val,v, map2.capacity());
}))
}
for mut func in funcs {
func(String::from("c"));
}
}
錯誤:
use of moved value: `map2`
value moved into closure here, in previous iteration of looprustcE0382
main.rs(12, 54): use occurs due to use in closure
main.rs(7, 9): move occurs because `map2` has type `HashMap<String, Vec<String>>`, which does not implement the `Copy` trait
我應該只使用可復制數據(如果是,如何?將 hashmap 包裝到自定義可復制結構中?),還是有其他方法?
編輯:解決方案
感謝@Masklinn:將不可復制的數據包裝到 Rc 中非常有效!
use std::{collections::HashMap, rc::Rc};
fn main() {
let mut map : HashMap<String, Vec<String>> = HashMap::new();
map.insert(String::from("a"), Vec::from([String::from("first")]));
map.insert(String::from("b"), Vec::from([String::from("first")]));
let map2 : HashMap<String, Vec<String>> = HashMap::new();
let rc_map2: Rc<HashMap<String, Vec<String>>> = Rc::new(map2);
let mut funcs: Vec<Box<dyn FnMut(String) -> ()>> = Vec::new();
for (key, val) in map {
let rc_map2_clone = rc_map2.clone();
funcs.push(Box::new(move |v| {
println!("{} : {:?} : {}, {}",key,val,v, rc_map2_clone.capacity());
}))
}
for mut func in funcs {
func(String::from("c"));
}
}
這里的正確解決方案是什么?
只需在閉包前添加關鍵字move
即可:
funcs.push(Box::new(move |v| {
println!("{} : {} : {}",key,val,v);
}))
默認情況下,lambda 嘗試推斷應該如何捕獲關閉的變量(引用、可變引用或值)。 然而,這完全基於使用情況。
這里你只是打印鍵和值,所以使用要求只是共享引用,因此在閉包中你有key: &String
和val: &String
。
通過使用move
閉包,您告訴 lambda 始終按值捕獲(並且您將管理捕獲,例如按值引用)。
通過在這里使用move
閉包,我們讓閉包擁有key
和value
String
s,因此它們的生命周期不再是問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.