2016-12-21 2 views
6

Je rencontre des problèmes de durée de vie avec une fonction particulière dans mon code. Je suis un tutoriel pour essayer d'apprendre Rust et SDL. Le tutoriel était un peu plus ancien et la librairie SDL a changé depuis son écriture, donc je suis en train de l'accompagner tout en l'adaptant à la dernière version de Rust-SDL.Impossible de déduire une durée de vie appropriée pour autoref en raison d'exigences contradictoires

Le problème de la durée de vie est dans cette fonction:

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

particulièrement avec la ligne self.ttf_context.load_font(Path::new(font_path), size as u16).ok(). La ligne commentée au-dessus est la méthode de chargement des polices de l'ancienne version de 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> 

L'objet struct pour cette mise en œuvre se présente comme suit:

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

La méthode tente de charger une police de Phi et de ttf_context charger dans le hashmap. Le compilateur Rust suggérait d'ajouter une durée de vie à self dans les paramètres de la fonction, ce qui, en faisant cela, provoquait un effet en cascade d'ajouter des durées de vie à toutes les méthodes appelant l'original, jusqu'à main() et n'aidait en rien. Depuis que je suis encore nouveau à Rust, je ne suis pas sûr où réside le conflit de la vie ou pourquoi cela se produit. En guise de supposition, je pense que l'objet Font qui est en train d'être généré est censé mourir à la fin de cette méthode mais à la place il est chargé dans un hashmap avec une durée de vie de 'window et ces deux conflits. Je ne connais pas assez Rust pour résoudre ce problème, ou si c'est correct.

Répondre

6

Voici un exemple plus petit qui reproduit le problème:

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

Le problème est en effet que vous avez construit un cas impossible. Plus précisément, le code énonce ces points:

  1. Phi va inclure une référence à un Window. Cette référence vit pour la vie 'window.
  2. Phi va inclure un Font, qui contient une référence. Cette référence vit pour la vie 'window.
  3. FontLoader renvoie qui contient une référence avec la durée de vie du chargeur. Cela est dû à l'inférence à vie, qui, lorsqu'il regarde étendu comme:

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

Ensuite, le code tente de charger un Font du FontLoader dans Phi, qui ne pas avoir la durée de vie 'window et stocker que Font en Phi. FontLoader (et donc Font) ne vit pas assez longtemps, il ne peut donc pas être stocké dans Phi.

Le compilateur a correctement empêché le code incorrect.


Votre prochaine tentative serait probablement d'introduire une seconde vie:

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

Cela va compiler en fait, mais ne probablement pas ce que vous voulez. Voir Why can't I store a value and a reference to that value in the same struct? pour plus d'informations.

Plus probablement, vous voulez prendre une référence au chargeur de police:

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

Ici, j'ai retitré la durée de vie car il n'est pas strictement la fenêtre plus.

+0

Je l'ai eu travailler avec votre aide! Merci! –

+0

__FontLoader (et donc Font) ne vit pas assez longtemps__: La durée de vie de 'FontLoader' n'est-elle pas la même que celle de Phi qui le contient? –

+0

@CarlLevasseur Oui, la durée de vie de 'FontLoader' et de son contenu' Phi' sont les mêmes. Pourquoi demandez-vous? – Shepmaster