由于需求冲突,无法推断autoref的适当生命周期

时间:2016-12-21 18:59:15

标签: rust sdl lifetime

我的代码中有特定功能的终身问题。我正在按照教程学习Rust和SDL。该教程稍微陈旧,SDL库自编写以来已经发生了变化,所以我一直在跟进,同时也适应最新版本的Rust-SDL。

终身问题出在这个函数中:

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>

该实现的struct对象如下所示:

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添加一个生命周期,当我这样做时,会导致级联效果,为每个调用原始方法的方法添加生命周期,一直到{{1}并且没有任何帮助。

由于我还不熟悉Rust,我不确定生命冲突所在的位置或为什么会发生这种情况。作为猜测,我认为正在生成的main()对象应该在该方法结束时死亡,而是将其加载到生命周期为{{的hashmap中。 1}}和那两个冲突。但是,我对Rust没有足够的了解来解决这个问题,或者说这是否正确。

1 个答案:

答案 0 :(得分:15)

这是一个重现问题的小例子:

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)
        }
    }
    
  4. 然后,代码尝试从Font FontLoader加载Phi拥有生命周期'window并存储该Font Phi FontLoaderFontPhi(以及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); } } )的活动时间不够长,因此无法存储在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); } } 中。

    编译器已正确防止错误代码。

    你的下一次尝试可能是引入第二次生命:

    pd

    这实际上会编译,但可能不会做你想要的。有关详细信息,请参阅Why can't I store a value and a reference to that value in the same struct?

    更有可能的是,您想要引用字体加载器:

    sns

    在这里,我已经重命名了生命周期,因为它不再严格用于窗口了。