关联类型的生命周期问题

Lifetime Issue with Associated Types

由于生命周期这个令人难以置信的恼人问题,上周我一直在抓狂。

当我尝试在 DataSource 中放置对 Buffer 的引用时出现问题,然后引用 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)
};

没有解决问题。

这允许您的示例编译:

pub struct DrawCommand<'a : 'b, 'b, R: Resources<'a>> {
    pub data_source: &'b R::DataSource
}

但是,我发现创建一个更简单的示例非常困难。据我所知,您遇到问题是因为您声明您将持有对本身具有引用的项目的引用,并且这两个引用需要具有共同的生命周期 ('a)。通过其他生世的某种组合,这实际上是不可能的。

添加第二个生命周期允许引用 DataSource 不同于 DataSource 本身的引用。

我仍然会尝试创建一个更小的示例。