You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Rust会报‘borrowed value does not live long enough’错误?

读取Excel转换对象的Rust生命周期问题

问题场景

我用Rust编写读取Excel表格数据并填充对象的程序,为了将Excel每行转换为Test对象,我为Test实现了From<std::slice::Iter<'_, calamine::DataType>> trait,代码如下:

use calamine::{open_workbook, DataType, Reader, Xlsx};
use std::convert::From;
use std::path::Path;
use std::slice::Iter;

#[derive(Debug)]
pub struct Test {
    pub field1: String,
    pub field2: String,
    pub field3: String,
}

impl From<Iter<'_, calamine::DataType>> for Test {
    fn from(mut val: Iter<'_, calamine::DataType>) -> Self {
        Test {
            field1: val.next().expect("failed").to_string(),
            field2: val.next().expect("failed").to_string(),
            field3: val.next().expect("failed").to_string(),
        }
    }
}

fn read_from_excel_sheet<'a, 'b, T: From<Iter<'a, calamine::DataType>>, P: AsRef<Path>>(
    wb_path: P,
    ws_name: &'b str,
) {
    let mut workbook: Xlsx<_> = open_workbook(wb_path).expect("Cannot open wb");

    if let Some(Ok(range)) = workbook.worksheet_range(ws_name) {
        for row in range.rows().skip(1) {
            let new_item = T::from(row.iter());
        }
    }
}

编译错误

编译时出现如下生命周期错误:

error[E0597]: `range` does not live long enough
  --> src/main.rs:31:20
   |
25 | fn read_from_excel_sheet<'a,'b, T: From<Iter<'a, calamine::DataType>>, P: AsRef<Path>>(wb_path: P, ws_name: &'b str) {
   |                          -- lifetime `'a` defined here
...
29 |     if let Some(Ok(range)) = workbook.worksheet_range(ws_name) {
   |                    ----- binding `range` declared here
30 |
31 |         for row in range.rows().skip(1) {
   |                    ^^^^^^^^^^^^ borrowed value does not live long enough
32 |
33 |             let new_item = T::from(row.iter());
   |                            ------------------- argument requires that `range` is borrowed for `'a`
...
36 |     }
   |     - `range` dropped here while still borrowed

我的疑惑

我能理解错误提示的内容,但不清楚range的生命周期为何会影响程序。range确实会在if块结束时被销毁,但此时没有任何引用指向它——new_item在每次迭代中创建并销毁,且Test的所有字段都是拥有所有权的String,完全不依赖任何外部数据。

可行的解决方案

经过多次尝试,我修改了函数的泛型约束,编译成功通过,但不清楚生效原因:

fn read_from_excel_sheet<'b, T: for<'a> From<Iter<'a, calamine::DataType>>, P: AsRef<Path>>(
    wb_path: P,
    ws_name: &'b str,
) {
    let mut workbook: Xlsx<_> = open_workbook(wb_path).expect("Cannot open wb");

    if let Some(Ok(range)) = workbook.worksheet_range(ws_name) {
        for row in range.rows().skip(1) {
            let new_item = T::from(row.iter());
        }
    }
}

原因解析

原代码的问题

原函数中声明了固定的生命周期'a,并要求T实现From<Iter<'a, calamine::DataType>>。编译器会认为,T的From实现必须使用这个全局的'a生命周期,但range的生命周期仅局限在if代码块内,远短于'a的作用域,因此编译器判定range被提前销毁但仍有引用依赖,触发错误。

修改后代码的原理

修改后的代码使用了高阶生命周期(HRTB,Higher-Rank Trait Bounds):for<'a> From<Iter<'a, calamine::DataType>>。这个约束的意思是:T必须能对任意生命周期'a都实现From<Iter<'a, calamine::DataType>>。

这样编译器就不会绑定到某个固定的'a,而是允许每次迭代时使用当前row的短生命周期——正好匹配我们的场景:Test的From实现只是读取迭代器中的数据,转换为拥有所有权的String,不会保留任何对原始数据的引用,完全可以适配任意短生命周期的迭代器。

内容的提问来源于stack exchange,提问作者JUSEOK KO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 19:06:07