2015-07-24 11 views
5

Wyciągam włosy z zeszłego tygodnia z powodu tego niesamowicie irytującego problemu z wcieleniami.Dożywotnia wersja z powiązanymi typami

Problem pojawia się, gdy próbuję umieścić odniesienie do Buffer wewnątrz DataSource, który następnie odwołuje się do DrawCommand. Otrzymuję komunikat o błędzie: vertex_data_source nie żyje wystarczająco długo.

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 } 

Mówi vertex_data_source musi być ważny dla przyrostka bloku następującym stwierdzeniem 3 w wierszu 60. Moja interpretacja tego błędu polega na tym, że przed linią 60 należy zdefiniować vertex_data_source. Ale w celu stworzenia vertex_data_source przede wszystkim potrzebuję dostępu do tych VertexAttributes na linii 60, więc nie mogę po prostu zamieniać kolejność.

Czuję, że wszystkie lata życia nad moim kodem muszą zostać podzielone na 2, a może po prostu usunięte, jednak próbowałem każdej kombinacji, która wydawała się rozsądna i nie mam pomysłów.

Poniżej znajduje się znacznie uproszczony przykład mojego kodu, który demonstruje problem. Byłbym wdzięczny za sprawdzenie zdrowego rozsądku i mam nadzieję, że świeży umysł będzie w stanie wykryć problem. (za każdym razem, zanim kilka dni grania stworzyło poprawkę, ale tym razem jestem zaskoczony).

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

Dziękuję bardzo z góry.

EDIT:

I został uaktualniony kod, aby lepiej odzwierciedlały moją rzeczywistą realizację.

Nawiasem mówiąc - zastępując w ten sposób:

let vertex_data_source = factory.create_data_source(vec!(vertices)); 

z tym:

let vertex_data_source = DataSource { 
    id: 0, 
    attributes: vec!(vertices), 
    current_element_array_buffer_binding: RefCell::new(None) 
}; 

nie rozwiązuje problemu.

+0

To całkiem długie ujęcie, ale czy możliwe jest, że od przeniesienia 'wierzchołków' do' create_data_source' i powracania z tym samym okresem życia, to życie już się skończyło, gdy funkcja wróci? – MartinHaTh

+0

Próbowałem to rozwiązać, ale uprościłeś kod do tego stopnia, że ​​nie mogę powiedzieć, co się dzieje. Rozwiązaniem jest "wyrwać kupkę pozornie bezsensownego kodu", ale to raczej nie jest to, czego chcesz. Na przykład, dlaczego 'attributes' przekazano do' create_data_source', kiedy nigdy nie jest używane? Dlaczego 'create_data_source' jest metodą na' Factory', kiedy nigdy się do niej nie odnosi? Dlaczego "a" jest używane w tej metodzie, mimo że w tym życiu nie ma * nic? Mogę ci powiedzieć, dlaczego dostajesz ten błąd, ale nie mogę zacząć sugerować, jak to naprawić bez lepszego zrozumienia tego, co robisz ... –

+0

Oto moja dotychczasowa decyzja: http: //is.gd/khBtaO –

Odpowiedz

0

Pozwala to Twój przykład kompilowania:

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

Jednak jestem znalezieniem że niezwykle trudno jest stworzyć bardziej minimalny przykład. Jak najlepiej mogę stwierdzić, masz problem, ponieważ deklarujesz, że będziesz odwoływał się do pozycji, która sama ma odniesienie i że te dwa odniesienia muszą mieć wspólne życie ('a). Przez niektóre kombinacje innych wcieleń jest to faktycznie niemożliwe.

Dodanie drugiego życia umożliwia odniesienie doDataSource różnić się od referencyjnego samego DataSource.

Nadal zamierzam spróbować stworzyć bardziej skondensowany przykład.

+0

Dziękuję bardzo, że dokładnie to, czego szukam! Wydaje mi się, że był to problem związany z czasem istnienia odniesienia do źródła danych, które musi się różnić od danych, na które wskazuje, ale nie wiedziałem, jak je wdrożyć. W szczególności: nie wiedziałem o składni "a": "b". Zakładam, że deklaruje, że '' a' musi być większe lub równe ''b'? – neon64

+0

@ neon64 Cieszę się, że mogę Ci pomóc, chociaż wciąż jestem zdenerwowany Nie mogę zrobić mniejszego przykładu, aby zademonstrować podstawowy problem. [To pytanie zwięźle opisuje całą składnię, o której mowa] (http://stackoverflow.com/q/30768063/155423). – Shepmaster

Powiązane problemy