我的代码中有一个特定函数存在终生问题。我正在学习一个教程,试图学习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
添加一个lifetime,当我这样做时,会对调用原始方法的每个方法添加lifetime产生级联效应,一直到main()
都没有任何帮助。因为我还没开始生锈,我不知道这一生的冲突在哪里,也不知道为什么会这样。作为猜测,我认为正在生成的
Font
对象应该随着该方法的结束而消亡,但是它被加载到一个生命周期为'window
的hashmap中,并且这两个冲突。不过,我对铁锈的了解还不足以修复它,或者说这是否正确。 最佳答案
下面是一个小例子,它再现了这个问题:
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();
| ^^^^
|
问题是你确实构造了一个不可能的案例。具体而言,该准则规定了以下几点:
Phi
将包含对aWindow
的引用。指的是生命周期的价值。'window
将包含一个包含引用的Phi
。指的是生命周期的价值。Font
返回一个'window
,其中包含对加载程序生存期中某个值的引用。这是由于生命周期推断,当展开时,它看起来像:impl FontLoader {
fn load<'a>(&'a self) -> Font<'a> {
Font(&self.0)
}
}
然后代码尝试从
FontLoader
中的Font
加载一个Font
,它没有生存期FontLoader
,并将该Phi
存储到'window
。Font
(因此Phi
)的寿命不够长,因此无法将其存储在FontLoader
中。编译器正确地防止了错误的代码。
你的下一个尝试可能是引入第二个生命:
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);
}
}
在这里,我重新命名了生命,因为它不再是严格意义上的窗口。
关于rust - 由于需求冲突,无法推断自动引用的适当生命周期,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41527212/