所有权 bug
2024年10月15日
3 min read
Rust
这个会有报错 borrowed value does not live long enough
title: "麻烦问一下闭包中引用变量无法通过编译的问题 - Rust语言中文社区"
image: "https://rustcc.cn/img/rust-logo.svg"
description: "昨天在搜索一个问题时发现一个例子:"
url: "https://rustcc.cn/article?id=d9e4c215-19b4-405f-ab79-82fc2b3449c0"
let task_root: &str = "../language-server/code_service_debug/work/task/stage2";
let project_id = "test_ts";
let csv_path = format!("{}/{}/User.ts.edges.wait", task_root, project_id);
let schema_name = "npctor";
let _stmt = "INSERT INTO testing.edge() VALUES ()";
println!("{:?}", csv_path);
let mut rdr = Reader::from_path(csv_path).expect("Error opening file");
let headers = rdr.headers().unwrap();
let columns: Vec<String> = headers.iter().map(|x| format!(r#""{}""#, x)).collect();
let column_str = columns.join(",");
println!("Headers {:?}", &column_str);
let mut count = 0;
let mut placeholders: Vec<String> = Vec::new();
let mut value: Vec<&str> = Vec::new();
// 遍历每一行
for result in rdr.records() {
let record = result.expect("Error reading record");
// 处理每一列数据
record.iter().for_each(|v| {
count += 1;
placeholders.push(format!("${}", count));
value.push(v);
});
// ...
}
原因与修复
原因:csv::StringRecord::iter() 返回的 &str 引用依赖于当前循环中的 record,而将些引用被压入了更长生命周期的 value: Vec<&str> 中。循环结束后 record 被释放,value 中的引用会悬垂,编译器据此报错 borrowed value does not live long enough。
修复思路:要么把要保留的数据“变成拥有者”,要么把使用范围缩到当前循环内。
方案 A:改为拥有所有权,存 String
let mut count = 0;
let mut placeholders: Vec<String> = Vec::new();
let mut values: Vec<String> = Vec::new();
for result in rdr.records() {
let record = result.expect("Error reading record");
for v in record.iter() {
count += 1;
placeholders.push(format!("${}", count));
values.push(v.to_string()); // 拥有数据所有权
}
}
方案 B:把“引用”的使用限制在单次循环内
for result in rdr.records() {
let record = result.expect("Error reading record");
let mut placeholders: Vec<String> = Vec::new();
let mut values: Vec<&str> = Vec::new();
for (i, v) in record.iter().enumerate() {
placeholders.push(format!("${}", i + 1));
values.push(v); // 仅在本次循环内使用
}
// 在这里同步使用 placeholders 和 values(例如执行一条插入),然后进入下一行
}