【发布时间】:2015-07-24 08:59:58
【问题描述】:
由于这个令人难以置信的令人讨厌的生命问题,我上周一直在拔头发。
当我尝试将Buffer 的引用放在DataSource 中时,就会出现问题,然后再引用DrawCommand。我收到错误消息:vertex_data_source 寿命不够长。
src/main.rs:65:23: 65:41 error:
src/main.rs:65 data_source: &vertex_data_source
^~~~~~~~~~~~~~~~~~
src/main.rs:60:51: 67:2 note: reference must be valid for the block suffix following statement 3 at 60:50...
src/main.rs:60 let vertices = VertexAttributes::new(&buffer);
src/main.rs:61
src/main.rs:62 let vertex_data_source = factory.create_data_source(vertices);
src/main.rs:63
src/main.rs:64 let command: DrawCommand<ResourcesImpl> = DrawCommand {
src/main.rs:65 data_source: &vertex_data_source
...
src/main.rs:62:67: 67:2 note: ...but borrowed value is only valid for the block suffix following statement 4 at 62:66
src/main.rs:62 let vertex_data_source = factory.create_data_source(vertices);
src/main.rs:63
src/main.rs:64 let command: DrawCommand<ResourcesImpl> = DrawCommand {
src/main.rs:65 data_source: &vertex_data_source
src/main.rs:66 };
src/main.rs:67 }
它说vertex_data_source 必须对第 60 行语句 3 之后的 块后缀有效。我对该错误的解释是 vertex_data_source 应该在第 60 行之前定义。但是首先要创建vertex_data_source,我需要访问第60行的VertexAttributes,所以我不能只是交换顺序。
我觉得我的代码中所有的 'a 生命周期都需要拆分为 2 或者可能只是删除,但是我已经尝试了所有看起来合理的组合,而且我还没有放弃想法。
下面是我的代码的一个大大简化的示例,它演示了这个问题。我真的很感激一个健全的检查,并希望一个新的头脑可能能够发现这个问题。 (在几天的摆弄之前的每次都产生了修复,但这次我被难住了)。
use std::cell::RefCell;
use std::marker::PhantomData;
pub struct DrawCommand<'a, R: Resources<'a>> {
pub data_source: &'a R::DataSource
}
pub trait Resources<'a> {
type DataSource: 'a;
type Buffer: 'a;
}
pub struct DataSource<'a> {
id: u32,
attributes: Vec<VertexAttributes<'a, ResourcesImpl<'a>>>,
current_element_array_buffer_binding: RefCell<Option<Buffer<'a>>>
}
pub struct Buffer<'a> {
context: &'a GraphicsContextImpl
}
pub struct GraphicsContextImpl;
pub struct ResourcesImpl<'a> {
phantom: PhantomData<&'a u32> // 'a is the lifetime of the context reference
}
impl<'a> Resources<'a> for ResourcesImpl<'a> {
type Buffer = Buffer<'a>;
type DataSource = DataSource<'a>;
}
struct Factory<'a> {
context: &'a GraphicsContextImpl
}
impl<'a> Factory<'a> {
/// Creates a buffer
fn create_buffer<T>(&self) -> Buffer<'a> {
Buffer {
context: self.context
}
}
fn create_data_source(&self, attributes: Vec<VertexAttributes<'a, ResourcesImpl<'a>>>) -> DataSource<'a> {
DataSource {
id: 0,
attributes: attributes,
current_element_array_buffer_binding: RefCell::new(None)
}
}
}
fn main() {
let context = GraphicsContextImpl;
let factory = Factory {
context: &context
};
let buffer = factory.create_buffer::<u32>();
let vertices = VertexAttributes::new(&buffer);
let vertex_data_source = factory.create_data_source(vec!(vertices));
let command: DrawCommand<ResourcesImpl> = DrawCommand {
data_source: &vertex_data_source
};
}
pub struct VertexAttributes<'a, R: Resources<'a>> {
pub buffer: &'a R::Buffer,
}
impl<'a, R: Resources<'a>> VertexAttributes<'a, R> {
pub fn new(buffer: &'a R::Buffer) -> VertexAttributes<'a, R> {
VertexAttributes {
buffer: buffer
}
}
}
非常感谢。
编辑:
我更新了代码以更好地反映我的实际实现。
顺便说一句 - 替换这个:
let vertex_data_source = factory.create_data_source(vec!(vertices));
有了这个:
let vertex_data_source = DataSource {
id: 0,
attributes: vec!(vertices),
current_element_array_buffer_binding: RefCell::new(None)
};
不能解决问题。
【问题讨论】:
-
这是一个相当长的镜头,但可能是因为您将
vertices移动到create_data_source,并以相同的生命周期返回,当函数返回时该生命周期已经结束? -
我试图解决这个问题,但你已经将代码简化到我无法判断发生了什么的程度。解决方案是“删除一堆看似毫无意义的代码”,但这不太可能是您想要的。例如,为什么
attributes从未使用过时会传递给create_data_source?为什么create_data_source是Factory上的一个方法,而它从不引用它?为什么在该方法中使用'a,尽管该生命周期涉及 nothing?我可以告诉你为什么你会收到这个错误,但如果没有更清楚地了解你在做什么,我无法开始建议如何解决它...... -
这是我在放弃之前得到的:is.gd/khBtaO
-
感谢@MartinHaTh 确实有效,但仅限于简化示例。我现在更新了我的测试代码,将
attributes实际存储在DataSource中。 -
非常感谢@DK。为详细分析。我已经更新了代码以更好地反映我正在尝试做的事情(现在实际使用了
attributes)。create_data_source是工厂方法,因为在我的实际实现中会有许多不同的工厂(OpenGL 工厂、DirectX 工厂等)。但是,即使我只是在工厂外创建vertex_data_source,问题仍然存在,所以我认为真正的问题在于DataSource结构本身的生命周期。