Bra*_*lko 18 sdl lifetime rust
我在代码中遇到了特定功能的终生问题.我正在学习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)
})
}
Run Code Online (Sandbox Code Playgroud)
尤其是线路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>
Run Code Online (Sandbox Code Playgroud)
该实现的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>>
}
Run Code Online (Sandbox Code Playgroud)
该方法试图从Phi加载字体ttf_context
并将其加载到hashmap中.Rust编译器建议我self
在函数参数中添加一个生命周期,当我这样做时,会产生级联效果,为每个调用原始方法的方法添加生命周期,一直到main()
没有任何帮助.
由于我还是Rust的新手,我不确定终身冲突所在的位置或者为什么会发生这种情况.作为猜测,我Font
认为正在生成的对象应该随着该方法的结束而死亡,而是将其加载到具有生命周期'window
和那两个冲突的hashmap中.但是,我对Rust没有足够的了解来解决这个问题,或者这是否正确.
She*_*ter 18
这是一个重现问题的小例子:
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() {}
Run Code Online (Sandbox Code Playgroud)
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:20:32
|
20 | let font = self.loader.load();
| ^^^^
|
Run Code Online (Sandbox Code Playgroud)
问题确实是你构建了一个不可能的案例.具体来说,代码说明了这些要点:
Phi
将包括对a的引用Window
.所提到的价值终生存在'window
.Phi
将包含一个Font
包含引用的a.所提到的价值终生存在'window
.FontLoader
返回一个Font
包含对带有加载器生存期的值的引用.这是由于终身推断,当扩展时看起来像:
impl FontLoader {
fn load<'a>(&'a self) -> Font<'a> {
Font(&self.0)
}
}
Run Code Online (Sandbox Code Playgroud)然后代码尝试Font
从FontLoader
in中加载a 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);
}
}
Run Code Online (Sandbox Code Playgroud)
这实际上会编译,但可能不会做你想要的.请参阅为什么我不能在同一个结构中存储值和对该值的引用?了解更多信息.
更有可能的是,您想要引用字体加载器:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我已经重命名了生命,因为它不再是严格的窗口了.