为何无法克隆存储可克隆构造器的Vec?
解决Rust中
dyn Ctor + 'static克隆时的生命周期逃逸错误 问题背景
我定义了结构体SVConstructor用于封装一组可克隆的Box<dyn Any>构造器,同时定义trait Ctor来处理dyn对象的克隆逻辑。单独实现trait Ctor或者单独编写SVConstructor的Clone都能正常编译,但同时启用所有代码时,即便已经标注了'static约束,依然会触发数据超出生命周期边界的错误。
原错误代码
use std::any::Any; pub struct SVConstructor { ctors: Vec<Box<dyn Ctor + 'static>>, } impl Clone for SVConstructor { fn clone(&self) -> Self { let Self { ctors } = self; let mut new_ctors: Vec<Box<dyn Ctor + 'static>> = Vec::new(); for ctor in ctors { let value: Box<dyn Ctor + 'static> = ctor.clone_box(); new_ctors.push(value); } Self { ctors: new_ctors } } } pub trait Ctor: Fn() -> Box<dyn Any + Send + Sync + 'static> + Send + Sync { fn clone_box(&self) -> Box<dyn Ctor + 'static>; } impl<T: Fn() -> Box<dyn Any + Send + Sync + 'static> + Send + Sync + Clone + 'static> Ctor for T { fn clone_box(&self) -> Box<dyn Ctor + 'static> { Box::new(self.clone()) } }
错误信息
error[E0521]: borrowed data escapes outside of associated function --> src/lib.rs:12:50 | 8 | fn clone(&self) -> Self { | ----- | | | `self` is a reference that is only valid in the associated function body | let's call the lifetime of this reference `'1` ... 12 | let value: Box<dyn Ctor + 'static> = ctor.clone_box(); | ^^^^^^^^^^^^^^^^ | | | `self` escapes the associated function body here | argument requires that `'1` must outlive `'static`
错误原因
Rust编译器默认会给trait方法的&self推断一个匿名生命周期,同时它会假设clone_box返回的Box<dyn Ctor + 'static>可能持有&self的引用。但实际上我们的实现是返回一个完全独立的克隆对象(通过self.clone()创建新实例),并不会持有原引用。这种误解导致编译器认为self的生命周期(仅在clone方法内有效)需要满足'static的要求,从而触发逃逸错误。
解决方案
给trait Ctor的clone_box方法添加生命周期约束,明确告诉编译器:返回的'static trait对象不依赖于&self的生命周期。
修复后的代码
use std::any::Any; pub struct SVConstructor { ctors: Vec<Box<dyn Ctor + 'static>>, } impl Clone for SVConstructor { fn clone(&self) -> Self { let Self { ctors } = self; let mut new_ctors: Vec<Box<dyn Ctor + 'static>> = Vec::new(); for ctor in ctors { let value: Box<dyn Ctor + 'static> = ctor.clone_box(); new_ctors.push(value); } Self { ctors: new_ctors } } } // 添加约束,明确实现该trait的类型必须是'static,消除生命周期误解 pub trait Ctor: Fn() -> Box<dyn Any + Send + Sync + 'static> + Send + Sync { fn clone_box(&self) -> Box<dyn Ctor + 'static> where Self: 'static; } impl<T: Fn() -> Box<dyn Any + Send + Sync + 'static> + Send + Sync + Clone + 'static> Ctor for T { fn clone_box(&self) -> Box<dyn Ctor + 'static> { Box::new(self.clone()) } }
也可以使用高阶生命周期的等价写法:
pub trait Ctor: Fn() -> Box<dyn Any + Send + Sync + 'static> + Send + Sync { for<'a> fn clone_box(&'a self) -> Box<dyn Ctor + 'static>; }
关键修改说明
通过在trait的clone_box方法中添加where Self: 'static约束,或者使用高阶生命周期for<'a>,我们明确告知编译器:实现该trait的类型必须是'static的,返回的trait object不会持有&self的引用,从而消除了编译器对生命周期逃逸的误判。
内容的提问来源于stack exchange,提问作者dspyz
相关产品推荐
相关产品推荐

