Я новичок в языке и все еще борюсь с проверкой заимствований. Я видел, что некоторые библиотеки используют функции new (), также известные как конструкторы без параметров, и это работает. В основном это означает, что возвращаемые данные создаются внутри области новой функции, а не удаляются в конце области действия new.
Когда я пробую это сам, программа проверки заимствований не пропускает этот код. Как сделать это, кроме передачи изменяемой ссылки i32 в качестве параметра конструктору.
Я что-то упускаю?
#[derive(Debug)]
struct B<'a> {
b: &'a i32
}
#[derive(Debug)]
struct A<'a> {
one: B<'a>
}
impl<'a> A<'a> {
fn new() -> A<'a> {
// let mut b = 10i32;
A {
one: B{b: &mut 10i32}
}
}
}
fn main() {
let a = A::new();
println!("A -> {:?}", a);
}
Ошибка компилятора.
main.rs:15:19: 15:24 error: borrowed value does not live long enough
main.rs:15 one: B{b: &mut 10i32}
^~~~~
main.rs:12:20: 17:3 note: reference must be valid for the lifetime 'a as defined on the block at 12:19...
main.rs:12 fn new() -> A<'a> {
main.rs:13 // let mut b = 10i32;
main.rs:14 A {
main.rs:15 one: B{b: &mut 10i32}
main.rs:16 }
main.rs:17 }
main.rs:12:20: 17:3 note: ...but borrowed value is only valid for the block at 12:19
main.rs:12 fn new() -> A<'a> {
main.rs:13 // let mut b = 10i32;
main.rs:14 A {
main.rs:15 one: B{b: &mut 10i32}
main.rs:16 }
main.rs:17 }
error: aborting due to previous error
По запросу, вот практический пример, с которым я пытаюсь работать. Есть эта библиотека графического интерфейса (Conrod), и в ней есть несколько шагов для ее создания. Как в примере ниже.
let assets = find_folder::Search::ParentsThenKids(3, 3)
.for_folder("assets").unwrap();
let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
let theme = Theme::default();
let glyph_cache = GlyphCache::new(&font_path).unwrap();
let ui = &mut Ui::new(glyph_cache, theme);
Мой план состоял в том, чтобы инкапсулировать рисунок приложения в структуру. У него будет конструктор и несколько вспомогательных методов. Чтобы это сработало, мне нужно было бы иметь поле с экземпляром типа conrod::Ui<GlyphCache<'a>>
, который является типом для переменной ui, указанной выше.
Я думаю, что добавление вещей в main (я имею в виду, что все распределения выполняются в main) может быть не лучшим способом сделать что-то.
let mut app_ui = app::AppUi::new(); // This would encapsulate all of the above configuration lines.
// use the ui here
for e in evets {
app_ui.handle_input();
app_ui.render();
}
Реализация AppUi. Он не завершен, но должен показать общую идею. Чтобы убедиться, что мы находимся на одной странице, для типа conrod::Ui<GlyphCache<'a>>
требуется параметр времени жизни. И я хочу, чтобы время жизни было таким же, как у структуры. Единственный способ, которым я знаю, как это сделать, - заставить структуру получить параметр времени жизни и передать его типу пользовательского интерфейса.
pub struct AppUi<'a> {
pub ui: conrod::Ui<GlyphCache<'a>>,
pub count: u16
}
impl<'a> AppUi<'a> {
pub fn new() -> AppUi<'a> {
let assets = find_folder::Search::ParentsThenKids(3, 3)
.for_folder("assets").unwrap();
let font_path = assets.join("FiraSans-Regular.ttf");
let theme = Theme::default();
let glyph_cache = GlyphCache::new(&font_path).unwrap();
AppUi {
ui: conrod::Ui::new(glyph_cache, theme),
count: 0
}
}
}
=======================
Решение, с которым я пошел, и оно сработало (по крайней мере, пока работает). Было создать вспомогательную функцию, которая возвращала бы glyph_cache и просто использовала это. Я не уверен, что это идиоматический Rust, пока просто воспользуюсь им. Наверное, стоит привыкнуть к работе с чекером заимствований.
pub struct AppUi<'a> {
pub ui: conrod::Ui<GlyphCache<'a>>,
pub count: u16
}
impl<'a> AppUi<'a> {
pub fn new() -> AppUi<'a> {
AppUi {
ui: conrod::Ui::new(GlyphCache::new(&get_default_font_path()).unwrap(), Theme::default()),
count: 0
}
}
}
pub fn get_default_font_path() -> PathBuf {
find_folder::Search::ParentsThenKids(3, 3)
.for_folder("assets")
.unwrap()
.join("FiraSans-Regular.ttf")
}