The borrowed value is not long enough for a compiler error for struct

I am new to the language and still struggling with the borrower. I saw that some libraries use new () aka constructor functions with no parameters, and this works. This basically means that the returned data is created inside the new function area and is not deleted at the end of the new area.

When trying this, the borrower himself does not skip this code. How to do this job, except passing the i32 mutable link as a parameter to the constructor.

Am I missing something?

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

Compiler error.

 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 

As requested, here is a practical example I'm trying to work with. There is this GUI library (Conrod), and it has some steps to create it. As in the example below.

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

My plan was to encapsulate the application drawing into a structure. This will have a constructor and several helper methods. To do this, I must have a field with an instance of type conrod::Ui<GlyphCache<'a>> , which is the type for the ui variable above.

I think adding things to the main (I mean all the distributions made basically) may not be the best way to do something.

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

Implementation of AppUi. This is not complete, but should show a general idea. To make sure that we are on the same page, the type conrod::Ui<GlyphCache<'a>> requires a lifetime parameter. And I want to have the same life as the structure. The only way I know how to do this is to make struct get the life parameter itself and pass it to the user interface type.

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

=========================

The solution I went with worked, and it worked at the end (at least it works now). A helper function was created that would return the glyph cache and just use it. I'm not sure if it will be idiomatic Rust, just use it for now. You must be used to working with the borrower.

 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") } 
+5
source share
2 answers

This is because &mut 10i32 does not live long enough in your program. You indicated that one will have the same lifetime as a , but a live longer than one , since i32 goes out of scope after completing new . This code will work differently:

 #[derive(Debug)] struct B<'a> { b: &'a i32 } #[derive(Debug)] struct A<'a> { one: B<'a> } impl<'a> A<'a> { fn new(x: &'a mut i32) -> A<'a> { // let mut b = 10i32; A { one: B{b: x} } } } fn main() { let mut x = 10i32; let a = A::new(&mut x); println!("A -> {:?}", a); } 

Note that x now resides as long as a , so your life spans are satisfied

+2
source

The key to understanding this is that the & link is a loan, not the value that belongs to it. Life annotations do not affect life expectancy; they only make sure that referents of the borrowed link survive the borrowed link, so that it will always be valid for dereferencing it.

A borrowed reference can refer to a value on the stack (statically allocated memory) or on the heap (dynamically allocated memory). Values ​​on the stack have a fairly long life; from the moment the variable is initialized to the end of the block when these values ​​are removed from the stack.

The values ​​on the heap belong to pointers that live on the stack; therefore, their lifespan is determined by the pointer to the stack that belongs to them. However, ownership can be moved between different variables, so you can have more flexible lifetimes for these values ​​if you move ownership to a pointer that refers to them from one variable in the stack to another.

If you write a function with a signature similar to the following:

 fn new() -> A<'a> {} 

you say that you will return A in which the contained links have some lifetime 'a , which is determined by the caller; but you cannot do this because you are not given links such as input. You cannot create a value with an arbitrary entry lifetime from the new function.

From the new function, what you usually want to return is eigenvalues; or perhaps values ​​with entries that are based on some input parameters, but you need to provide these links as input parameters.

This can help if you tell a little more about what you are trying to do, rather than just providing an example of toys. There are a few possible things you could try to do here, but with just an example of toys it’s hard to determine what to describe. What is the purpose of returning the object containing the link? This means that the object can be selected in the form of a heap and, therefore, must move only one pointer at a time, and not copy the entire value? In this case, you probably need Box or Vec . Does this mean that it can refer to some stack assigned to a variable? Then you need to select this in the containing stack of the stack and pass the link with this lifetime to your function, so there is a variable with an appropriate lifetime for its reference. If you are simply trying to return an object containing an integer, then you can do this if the object contains an integer directly, but does not contain a reference to it.

+6
source

All Articles