返回博客列表

所有权 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(例如执行一条插入),然后进入下一行
}

评论讨论

使用 GitHub 账号登录参与讨论

加载评论中...