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

Rust编译报错:main函数结束时引用仍被借用,求解决方案

Rust实现光线追踪时的生命周期借用问题解决

问题背景

我正在学习《Ray Tracing in One Weekend》并使用Rust实现。代码中定义了Hittable和Material两个trait,Hittable trait为Sphere等对象实现hit方法,每种对象包含对应材质(如Glass)。实际项目中,Sphere结构体和HitRecord结构体(用于hit方法传递结果的可变引用)均包含&dyn Material,因此为相关trait和结构体添加了生命周期参数。但编译时编译器提示main函数结束时引用仍处于借用状态。

问题代码

trait Hittable<'a> {
    fn hit(&self);
}

trait Material {
    fn result(&self);
}

struct Glass;

impl Material for Glass {
    fn result(&self) {
        println!("Glass is broken!");
    }
}

struct Sphere<'a> {
    name: String,
    mat_ptr: &'a dyn Material,
}

impl<'a> Hittable<'a> for Sphere<'a> {
    fn hit(&self) {
        println!("Name is {}", self.name);
        self.mat_ptr.result();
    }
}

struct HT<'a> {
    pub objects: Vec<Box<dyn Hittable<'a>>>,
}

fn main() {
    let mut list = HT { objects: vec![] };
    let surface_material = Glass;
    let s = Sphere {
        name: String::from("球"),
        mat_ptr: &surface_material,
    };
    list.objects.push(Box::new(s));
}

错误信息

Compiling rust_test v0.1.0 (/home/hnyls2002/rust_test)
error[E0597]: `surface_material` does not live long enough
  --> src/main.rs:38:18
   |
38 |         mat_ptr: &surface_material,
   |                  ^^^^^^^^^^^^^^^^^
   |                  |
   |                  borrowed value does not live long enough
   |                  cast requires that `surface_material` is borrowed for `'static`
...
41 | }
   | - `surface_material` dropped here while still borrowed

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

问题原因

错误核心在于:将Sphere包装进Box<dyn Hittable<'a>>时,Rust默认要求该trait对象满足'static生命周期(除非显式标注)。而surface_material是main函数栈上的局部变量,生命周期仅到main函数结束,但list持有了对它的引用,导致引用生命周期短于被引用值的销毁时机,违反了Rust的借用规则。

解决方案

方案1:使用引用计数智能指针(推荐)

光线追踪场景中多个物体可能共享同一种材质,用Arc<dyn Material>可安全共享材质实例,彻底规避生命周期问题:

use std::sync::Arc;

trait Hittable {
    fn hit(&self);
}

trait Material {
    fn result(&self);
}

struct Glass;

impl Material for Glass {
    fn result(&self) {
        println!("Glass is broken!");
    }
}

struct Sphere {
    name: String,
    mat_ptr: Arc<dyn Material>,
}

impl Hittable for Sphere {
    fn hit(&self) {
        println!("Name is {}", self.name);
        self.mat_ptr.result();
    }
}

struct HT {
    pub objects: Vec<Box<dyn Hittable>>,
}

fn main() {
    let mut list = HT { objects: vec![] };
    let surface_material = Arc::new(Glass);
    let s = Sphere {
        name: String::from("球"),
        mat_ptr: surface_material.clone(),
    };
    list.objects.push(Box::new(s));
}

方案2:调整变量声明顺序

利用Rust反向销毁变量的规则,让被引用的材质先声明、后销毁,保证其生命周期长于持有引用的list:

trait Hittable<'a> {
    fn hit(&self);
}

trait Material {
    fn result(&self);
}

struct Glass;

impl Material for Glass {
    fn result(&self) {
        println!("Glass is broken!");
    }
}

struct Sphere<'a> {
    name: String,
    mat_ptr: &'a dyn Material,
}

impl<'a> Hittable<'a> for Sphere<'a> {
    fn hit(&self) {
        println!("Name is {}", self.name);
        self.mat_ptr.result();
    }
}

struct HT<'a> {
    pub objects: Vec<Box<dyn Hittable<'a>>>,
}

fn main() {
    let surface_material = Glass;
    let mut list = HT { objects: vec![] };
    let s = Sphere {
        name: String::from("球"),
        mat_ptr: &surface_material,
    };
    list.objects.push(Box::new(s));
}

方案3:将材质移到堆上获得'static生命周期

把材质实例分配到堆上,使其拥有'static生命周期,满足trait对象的约束:

trait Hittable<'a> {
    fn hit(&self);
}

trait Material {
    fn result(&self);
}

struct Glass;

impl Material for Glass {
    fn result(&self) {
        println!("Glass is broken!");
    }
}

struct Sphere<'a> {
    name: String,
    mat_ptr: &'a dyn Material,
}

impl<'a> Hittable<'a> for Sphere<'a> {
    fn hit(&self) {
        println!("Name is {}", self.name);
        self.mat_ptr.result();
    }
}

struct HT<'a> {
    pub objects: Vec<Box<dyn Hittable<'a>>>,
}

fn main() {
    let mut list = HT { objects: vec![] };
    // 将材质分配到堆上,获得'static生命周期
    let surface_material = Box::new(Glass) as Box<dyn Material>;
    let s = Sphere {
        name: String::from("球"),
        mat_ptr: &*surface_material,
    };
    list.objects.push(Box::new(s));
    // 注意:surface_material需与list同生命周期,不能提前销毁
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 23:31:37