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

关于Rust生命周期的疑问:两段相似代码为何一错一正?

Rust生命周期困惑:Box与引用的行为差异

原本以为自己已清晰理解Rust生命周期,却发现知识盲区——以下第一段用Box包裹trait对象的代码会触发E0597错误,但将Box替换为引用后的第二段代码却能正常运行,想知道原因:

第一段报错代码

struct Token<'a> {
    slice: &'a str,
}

struct WrappedToken<'a>(&'a Token<'a>);

trait ToWrappedToken<'a> {
    fn to(&'a self) -> WrappedToken<'a>;
}

impl<'a> ToWrappedToken<'a> for Token<'a> {
    fn to(&'a self) -> WrappedToken<'a> {
        WrappedToken(self)
    }
}

fn to_wrap<'a>(token: Token<'a>) -> Box<dyn ToWrappedToken<'a> + 'a> {
    Box::new(token)
}

fn main() {
    let token = Token {
        slice: "It's working well.",
    };
    let r = to_wrap(token);
    r.to();
}

错误信息

error[E0597]: `*r` does not live long enough
  --> src/main.rs:26:5
   |
25 |     let r = to_wrap(token);
   |         - binding `r` declared here
26 |     r.to();
   |     ^ borrowed value does not live long enough
27 | }
   | -
   | |
   | `*r` dropped here while still borrowed
   | borrow might be used here, when `r` is dropped and runs the destructor for type `Box<dyn ToWrappedToken<'_>>`

For more information about this error, try `rustc --explain E0597`.

第二段正常代码

struct Token<'a> {
    slice: &'a str,
}

struct WrappedToken<'a>(&'a Token<'a>);

trait ToWrappedToken<'a> {
    fn to(&'a self) -> WrappedToken<'a>;
}

impl<'a> ToWrappedToken<'a> for Token<'a> {
    fn to(&'a self) -> WrappedToken<'a> {
        WrappedToken(self)
    }
}

fn to_wrap<'a>(token: &'a Token<'a>) -> &'a dyn ToWrappedToken<'a> {
    token
}

fn main() {
    let token = Token {
        slice: "It's working well.",
    };

    let r = to_wrap(&token);

    r.to();
}

核心原因分析

两段代码的差异本质是被包裹对象的生命周期与trait方法要求的引用生命周期是否匹配,以及Rust对trait对象析构的安全检查:

  1. Box版本报错的关键原因:

    • to_wrap将Token移动到Box中,此时Box内Token的生命周期是变量r的生命周期(从创建到main函数结束)。
    • ToWrappedToken<'a> trait的to方法要求接收&'a self——这里的'a是Token结构体的生命周期参数(对应slice的'static生命周期)。
    • 调用r.to()时,Box自动解引用为&*r,但*r的生命周期短于'a,无法满足&'a self的要求。
    • 更重要的是,Rust无法确定trait对象的析构函数是否会保留to方法返回的WrappedToken中的引用。当r被销毁时,*r`会先被释放,若析构函数尝试访问已销毁的对象,就会产生悬垂引用,因此编译器直接报错阻止这种风险。
  2. 引用版本正常的逻辑:

    • to_wrap返回的&'a dyn ToWrappedToken<'a>直接指向原Token实例,其生命周期'a与Token的生命周期参数完全一致。
    • 调用r.to()时,&'a self就是对原Token的引用,生命周期完全匹配,编译器可以确认Token的生命周期足够长,不会在引用使用期间被销毁,因此通过安全检查。

内容的提问来源于stack exchange,提问作者Irfan Hossain Bhuiyan Student

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 18:58:16