2016-12-21 23 views
6

Mam problemy z życiem z określoną funkcją w moim kodzie. Podążam za tutorialem próbując poznać Rust i SDL. Samouczek był nieco starszy i biblioteka SDL zmieniła się od czasu jego napisania, więc podążam za nim, jednocześnie dostosowując go do najnowszej wersji Rust-SDL.Nie można określić odpowiedniego okresu istnienia autoref z powodu sprzecznych wymagań.

problemem

Czas życia jest w tej funkcji:

pub fn ttf_str_sprite(&mut self, text: &str, font_path: &'static str, size: i32, color: Color) -> Option<Sprite> { 
    if let Some(font) = self.cached_fonts.get(&(font_path, size)) { 
     return font.render(text).blended(color).ok() 
      .and_then(|surface| self.renderer.create_texture_from_surface(&surface).ok()) 
      .map(Sprite::new) 
    } 
    //::sdl2_ttf::Font::from_file(Path::new(font_path), size).ok() 
    self.ttf_context.load_font(Path::new(font_path), size as u16).ok() 
     .and_then(|font| { 
      self.cached_fonts.insert((font_path, size), font); 
      self.ttf_str_sprite(text, font_path, size, color) 
    }) 
} 

zwłaszcza linii self.ttf_context.load_font(Path::new(font_path), size as u16).ok(). Skomentowana linia powyżej to stara metoda ładowania czcionek w wersji SDL.

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements 
    --> src\phi/mod.rs:57:26 
    | 
57 |   self.ttf_context.load_font(Path::new(font_path), size as u16).ok() 
    |       ^^^^^^^^^ 
    | 
help: consider using an explicit lifetime parameter as shown: fn ttf_str_sprite(&'window mut self, text: &str, font_path: &'static str, 
       size: i32, color: Color) -> Option<Sprite> 

Przedmiotem struct dla tej realizacji wygląda następująco:

pub struct Phi<'window> { 
    pub events: Events, 
    pub renderer: Renderer<'window>, 
    pub ttf_context: Sdl2TtfContext, 

    cached_fonts: HashMap<(&'static str, i32), ::sdl2_ttf::Font<'window>> 
} 

Metoda próbuje załadować czcionkę z Phi na ttf_context i załadować go do hashmap. Kompilator Rust zaproponował dodanie okresu życia do self w parametrach funkcji, które, gdy to zrobiłem, powodowały efekt kaskadowy dodawania wcieleń do każdej metody wywołującej pierwotną, aż do main() i nic nie pomogły.

Ponieważ wciąż jestem nowy w Rust, nie jestem pewien, gdzie znajduje się konflikt w życiu lub dlaczego tak się dzieje. Domyślam się, że obiekt Font, który jest generowany, powinien umrzeć wraz z końcem tej metody, ale zamiast tego jest ładowany do mapy mieszającej o czasie trwania 'window i tych dwóch konfliktów. Nie wiem jednak wystarczająco dużo o Rustu, żeby to naprawić, a nawet jeśli to prawda.

Odpowiedz

6

Oto przykład, który odtwarza mniejszy problem:

struct FontLoader(String); 
struct Font<'a>(&'a str); 

impl FontLoader { 
    fn load(&self) -> Font { 
     Font(&self.0) 
    } 
} 

struct Window; 

struct Phi<'window> { 
    window: &'window Window, 
    loader: FontLoader, 
    font: Option<Font<'window>>, 
} 

impl<'window> Phi<'window> { 
    fn do_the_thing(&mut self) { 
     let font = self.loader.load(); 
     self.font = Some(font); 
    } 
} 

fn main() {} 
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements 
    --> src/main.rs:20:32 
    | 
20 |   let font = self.loader.load(); 
    |        ^^^^ 
    | 

Problemem jest to, że rzeczywiście zostały skonstruowane niemożliwy przypadek. Konkretnie, kod wskazuje te punkty:

  1. Phi będzie zawierać odniesienie do Window. To odniesienie żyje na całe życie 'window.
  2. Phi będzie zawierać Font, który zawiera odniesienie. To odniesienie żyje na całe życie 'window.
  3. FontLoader zwraca Font który zawiera odniesienia z życia ładowarki. Wynika to z wnioskowania dożywotnią, która po rozwinięciu wygląda następująco:

    impl FontLoader { 
        fn load<'a>(&'a self) -> Font<'a> { 
         Font(&self.0) 
        } 
    } 
    

Następnie kod próbuje załadować Font od FontLoader w Phi, który nie mają żywotność 'window i przechowywać że Font w Phi. FontLoader (i tym samym Font) nie jest wystarczająco długi, więc nie można go zapisać w Phi.

Kompilator poprawnie uniemożliwił wprowadzenie niepoprawnego kodu.


Twoja kolejna próba będzie prawdopodobnie wprowadzenie drugiego życia:

struct Phi<'window, 'font> { 
    window: &'window Window, 
    loader: FontLoader, 
    font: Option<Font<'font>>, 
} 

impl<'window, 'font> Phi<'window, 'font> { 
    fn do_the_thing(&'font mut self) { 
     let font = self.loader.load(); 
     self.font = Some(font); 
    } 
} 

To rzeczywiście skompilować, ale prawdopodobnie nie robić, co chcesz. Aby uzyskać więcej informacji, patrz Why can't I store a value and a reference to that value in the same struct?.

Bardziej prawdopodobne, chcesz mieć odniesienie do ładowarki czcionki:

struct Phi<'a> { 
    window: &'a Window, 
    loader: &'a FontLoader, 
    font: Option<Font<'a>>, 
} 

impl<'a> Phi<'a> { 
    fn do_the_thing(&mut self) { 
     let font = self.loader.load(); 
     self.font = Some(font); 
    } 
} 

Tutaj mam przemianowany na całe życie, gdyż nie jest to absolutnie za oknem już.

+0

Mam to działa z Twoją pomocą! Dzięki! –

+0

__FontLoader (a tym samym Font) nie żyje wystarczająco długo__: Czy żywotność 'FontLoadera' nie jest taka sama jak Phi, która go zawiera? –

+0

@CarlLevasseur tak, życie "FontLoader" i jego zawierające 'Phi' są takie same. Dlaczego pytasz? – Shepmaster

Powiązane problemy