2015-07-24 4 views
5

Я вытаскиваю свои волосы за последнюю неделю из-за этой невероятно раздражающей проблемы со временем жизни.Пожизненная проблема со связанными типами

Проблема возникает, когда я пытаюсь поместить ссылку на 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 должен быть действительным для блока суффикса после заявления 3 в строке 60. Моя интерпретация этой ошибки заключается в том, что vertex_data_source должен быть определен до строки 60. Но для создания vertex_data_source в первую очередь мне нужен доступ к тем VertexAttributes на линии 60, поэтому я не могу просто поменять порядок.

Я чувствую, что все '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 
     } 
    } 
} 

Большое спасибо за внимание.

EDIT:

Я обновил код, чтобы лучше отразить мою фактическую реализацию.

Кстати - замена этого:

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) 
}; 

Не решает эту проблему.

+0

Это довольно длинный снимок, но может быть, так как вы перемещаете «вершины» в 'create_data_source' и возвращаетесь с тем же временем жизни, это время жизни уже завершено, когда функция возвращается? – MartinHaTh

+0

Я пытался это исправить, но вы упростили код до такой степени, что я не могу сказать, что происходит. Решение - «вырезать кучу, казалось бы, бессмысленного кода», но это вряд ли будет тем, что вы хотите. Например, почему 'attributes 'передается' create_data_source', когда он никогда не используется? Почему 'create_data_source' метод на' Factory', когда он никогда не ссылается на него? Почему '' a' используется в этом методе, несмотря на включение * ничего * с этой жизнью? Я могу сказать вам, почему вы получаете эту ошибку, но я не могу начать предлагать, как исправить это, не имея более четкого представления о том, что вы делаете ... –

+0

Вот как я до этого отказался: http: //is.gd/khBtaO –

ответ

0

Это позволяет ваш пример компиляции:

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

Однако, я нахожу это чрезвычайно трудно создать более минимальный пример. Насколько я могу судить, у вас есть проблема, потому что вы заявляете, что будете хранить ссылку на элемент, который сам имеет ссылку, и что эти две ссылки должны иметь общий срок службы ('a). Благодаря некоторой комбинации других жизней это на самом деле невозможно.

Добавление второго срока службы позволяет ссылка кDataSource отличаться от эталонного самого DataSource.

Я все еще пытаюсь создать более миниатюрный пример.

+0

Большое вам спасибо, что именно так я и ищу! Я действительно думал, что это проблема со временем жизни ссылки на источник данных, который должен отличаться от данных, на которые он указывает, но я не знал, как его реализовать. В частности: я не знал о синтаксисе ''a:' b'. Я предполагаю, что объявляет, что '' a' должен быть больше или равен '' b'? – neon64

+0

@ neon64 Рад помочь, хотя я все еще расстроен, я не могу сделать меньший пример, чтобы продемонстрировать основную проблему. [Этот вопрос кратко описывает рассматриваемый синтаксис жизни] (http://stackoverflow.com/q/30768063/155423). – Shepmaster

Смежные вопросы