【问题标题】:Lifetime Issue with Associated Types相关类型的终身问题
【发布时间】: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_sourceFactory 上的一个方法,而它从不引用它?为什么在该方法中使用'a,尽管该生命周期涉及 nothing?我可以告诉你为什么你会收到这个错误,但如果没有更清楚地了解你在做什么,我无法开始建议如何解决它......
  • 这是我在放弃之前得到的:is.gd/khBtaO
  • 感谢@MartinHaTh 确实有效,但仅限于简化示例。我现在更新了我的测试代码,将attributes 实际存储在DataSource 中。
  • 非常感谢@DK。为详细分析。我已经更新了代码以更好地反映我正在尝试做的事情(现在实际使用了attributes)。 create_data_source 是工厂方法,因为在我的实际实现中会有许多不同的工厂(OpenGL 工厂、DirectX 工厂等)。但是,即使我只是在工厂外创建 vertex_data_source,问题仍然存在,所以我认为真正的问题在于 DataSource 结构本身的生命周期。

标签: rust lifetime


【解决方案1】:

这允许您的示例编译:

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

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

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

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

【讨论】:

  • 非常感谢,这正是我正在寻找的!我确实认为这是对数据源的引用的生命周期需要与它指向的数据不同的问题,但我不知道如何实现它。具体来说:我不知道'a: 'b 语法。我假设声明 'a 必须大于或等于 'b?
  • @neon64 很高兴能提供帮助,尽管我仍然很沮丧,但我无法举一个更小的例子来展示核心问题。 This question succinctly describes the lifetime syntax in question.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-28
  • 2019-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多