我正在Rust的一个玩具射线追踪器项目中工作,并且挂了一个与生命有关的错误。我将代码简化为以下独立的失败案例:
struct Material {}
pub struct Sphere<'a> {
material: &'a Material,
}
pub trait AnySceneObject {}
impl<'a> AnySceneObject for Sphere<'a> {}
pub struct Scene {
objects: Vec<Box<AnySceneObject>>,
}
fn main() {
let material = Material {};
let boxed_sphere: Box<AnySceneObject> = Box::new(Sphere { material: &material });
Scene { objects: vec![boxed_sphere] };
}
Run Code Online (Sandbox Code Playgroud)
哪个抱怨
error[E0597]: `material` does not live long enough
--> main.rs:17:74
|
17 | let boxed_sphere: Box<AnySceneObject> = Box::new(Sphere { material: &material });
| ^^^^^^^^ does not live long enough
18 | Scene { objects: vec![boxed_sphere] };
19 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error(s)
Run Code Online (Sandbox Code Playgroud)
我想使用特征在场景中定义对象,但是我希望Scene对象拥有它们。我目前的理解是,这意味着我需要Box或等同的东西,因为特征对象的大小未知。
我还希望对象共享对Materials的引用,因为不会有太多对象,尽管它们相对简单且Copy能够,但我不希望从字面上看成千上万的同一事物的相同副本(因此使用&'a Material)。
我很困惑为什么它是有问题的传递&material虽然这里:因为值之后最新一,不会Scene首先被丢弃,从而boxed_sphere被丢弃(因为它现在拥有一个Vec拥有该Box),它然后,允许material以掉线,没问题吗?好像它应该至少与该函数中的其他两个值一样长,因为我要保留带有material整个函数范围名称的值。
同样令人困惑的是,Scene出于我不理解的原因,注释掉了修复实例的实例。
首先,如果您有成千上万个场景对象,将它们放在盒子中(基本上是一个堆对象)绝对不是一个好主意。
调用该错误是因为Box的内容不得包含任何可能过期的引用。您可以四处Box走动,直到过程结束,它才可能被删除,因此它保存的所有引用都必须具有'static生命周期。
您可以通过使用Box<T + 'a>来指示它将有有限的寿命来对其进行修复:
pub struct Scene<'a> {
objects: Vec<Box<AnySceneObject + 'a>>,
}
Run Code Online (Sandbox Code Playgroud)
您还可以Vec<&Trait>用来存储对实现特征的不同对象的引用的集合。以下代码编译:
pub struct Scene<'a> {
objects: Vec<&'a AnySceneObject>,
}
fn main() {
let material = Material {};
let sphere = Sphere { material: &material };
Scene {
objects: vec![&sphere]
};
}
Run Code Online (Sandbox Code Playgroud)
如果您知道特征的所有可能实现,则可以将其替换为枚举。这将使代码更具性能,因为您将拥有拥有枚举而不是引用的向量。
| 归档时间: |
|
| 查看次数: |
2189 次 |
| 最近记录: |