2016-12-21 1 views
6

У меня возникают проблемы с продолжительностью жизни с определенной функцией в моем коде. Я слежу за учебником, пытаясь узнать Rust и SDL. Учебник был немного старше, и библиотека SDL изменилась с момента его написания, поэтому я слежу за ней, а также адаптирую ее к последней версии Rust-SDL.Невозможно вывести подходящий срок службы для autoref из-за противоречивых требований

проблема

Время жизни в этой функции:

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

особенно с линией self.ttf_context.load_font(Path::new(font_path), size as u16).ok(). Вышеупомянутая строка над ним - это метод загрузки шрифтов старой 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> 

Объект структура для этой реализации выглядит следующим образом:

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

Метод пытается загрузить шрифт из Phi-х ttf_context и загрузить его в HashMap. Компилятор Rust предложил мне добавить продолжительность жизни до self в параметры функции, которые, когда я это делал, вызвали каскадный эффект добавления времени жизни к каждому методу, вызывающему исходный, вплоть до main() и ничего не помогли.

Поскольку я все еще новичок в Rust, я не уверен, где живет конфликт продолжительности жизни или почему это происходит. Думаю, что я думаю, что создаваемый объект Font должен умереть с концом этого метода, но вместо этого он загружается в хэш-карту со временем жизни 'window и этими двумя конфликтами. Я не знаю достаточно о Rust, чтобы исправить это, хотя, если это даже правильно.

ответ

6

Вот меньший пример, который воспроизводит проблему:

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(); 
    |        ^^^^ 
    | 

Проблема заключается в том, что вы действительно построили невозможное дело. В частности, код утверждает эти пункты:

  1. Phi будет включать в себя ссылку на Window. Эта ссылка живет на всю жизнь 'window.
  2. Phi будет содержать Font, в котором содержится ссылка. Эта ссылка живет на всю жизнь 'window.
  3. FontLoader возвращает Font, который содержит ссылку с указанием срока службы загрузчика. Это связанно с пожизненными умозаключениями, которые при развернутом выглядят следующим образом:

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

Затем код пытается загрузить Font из FontLoader в Phi, который не имеют срок службы 'window и хранить, что Font в Phi. FontLoader (и, следовательно, Font) недолго проживает, поэтому его нельзя хранить в Phi.

Компилятор правильно предотвратил неправильный код.


Ваша следующая попытка, вероятно, будет ввести второй жизни:

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

Это будет компилировать, но, вероятно, не делать то, что вы хотите. См. Why can't I store a value and a reference to that value in the same struct? для получения дополнительной информации.

Скорее всего, вы хотите взять ссылку на загрузчик шрифта:

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

Здесь я переименовал всю жизнь, как это не только для окна больше.

+0

Я получил это с вашей помощью! Благодаря! –

+0

__FontLoader (и, следовательно, Font) не достаточно долгое время. _: Не существует ли время жизни «FontLoader» так же, как и Phi, который его содержит? –

+0

@CarlLevasseur Да, время жизни 'FontLoader' и его содержащих' Phi' одинаково. Почему вы спрашиваете? – Shepmaster

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