I have following code and don't know how to get it working:
fn new_int<'a>() -> &'a isize {
&5
}
fn main() {
let x = new_int();
}
Or another attempt:
fn new_int<'a>() -> &'a isize {
let a: &'a isize = &5;
a
}
fn main() {
let x = new_int();
}
Lifetime of a variable is defined as for how much time period a variable is occupying a valid space in the system's memory or lifetime is the period between when memory is allocated to hold the variable and when it is freed. Once the variable is out of scope its lifetime ends.
The lifetime of a variable is the time during which the variable stays in memory and is therefore accessible during program execution. The variables that are local to a method are created the moment the method is activated (exactly as formal parameters) and are destroyed when the activation of the method terminates.
The scope of a declaration is the part of the program for which the declaration is in effect. C/C++ use lexical scoping. The lifetime of a variable or object is the time period in which the variable/object has valid memory. Lifetime is also called "allocation method" or "storage duration."
Lifetimes are what the Rust compiler uses to keep track of how long references are valid for. Checking references is one of the borrow checker's main responsibilities. Lifetimes help the borrow checker ensure that you never have invalid references.
You can't. A lifetime parameter does not allow you to choose how long a value lives, it only allows you to communicate to the compiler that two or more references are "related" to the same memory and are expected to share the same lifetime.
A function (like new_int
in your case) can allocate memory in two ways:
A reference (&
) is a pointer to an area of memory. It can point to the local stack, or to the heap. Since dynamic allocations are much more expensive in terms of performance than writing on the stack, Rust uses the stack by default (you have to use a Box to perform a dynamic allocation).
So, in a nutshell, this is why your code is illegal:
fn new_int<'a>() -> &'a isize {
let a: &'a isize = &5; // write 5 on the function's local stack
a // return a pointer to that area of memory
} // the function ends and its stack (where I wrote 5) is destroyed
// so the pointer I'm trying to return is no longer valid
You can either return the value
fn new_int() -> isize {
5
}
fn main() {
let a = new_int(); // the value 5 (not a pointer) is copied into a
}
or perform a dynamic allocation (which is overkill in case of an isize but might make sense if you're actually working with a big structure)
fn new_int() -> Box<isize> {
Box::new(5) // a Box allocates memory and writes in the heap
}
fn main() {
let a = *new_int();
}
alternatively, you can allocate memory outside of the function and mutate it in the function. You don't typically do it for a primitive type, but it makes sense in some scenarios (e.g. streaming of data):
// new_int does not return anything. Instead it mutates
// the old_int in place
fn new_int(old_int: &mut isize) {
*old_int = 5;
}
fn main() {
let mut a = 2; // memory for an int is allocated locally
// in main()
new_int(&mut a); // a mutable reference to that memory is passed
// to new_int, that overwrites it with another value
}
As @dk mentions in the comment below,, in this specific case (i.e. your function always returns 5 or some other statically known value, not something calculated dynamically by the function) you can also return a reference with a 'static
lifetime:
fn new_int<'a>() -> &'a isize {
static FIVE: isize = 5;
&FIVE
}
You can read more about 'static
in the Rust Reference.
As of Rust 1.21, this "static promotion" is now performed for you automatically and your original code compiles. It creates the equivalent of the static FIVE
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With