The Rust book states:
Each value in Rust has an owner
It does not explain what type of entity this owner is. Is it a programmer? a variable? A statement? A code block?
What is the precise definition of what type of entity can be a 'value owner'?
Usually, owners are variables or fields; they are responsible for dropping the value owned. However, more surprisingly, even the program binary can be an owner too. As an example, that's the case for string literals:
let s = "Hello World";
The string literal above is stored in the program binary itself, s is just a reference to it. As such, its lifetime is 'static, i.e., the literal lifespan corresponds to the program execution.
As other people stated, owners are variables or fields.
I just wanted to add a practical example:
fn main() {
// s is the owner of the string.
let s: String = String::from("Hello!");
// r is the owner of the reference, which in turn references s.
// It can access the string, but does not own it.
let r: &String = &s;
// That means if we drop `s`, which owns the string, the string gets destroyed.
drop(s);
// Meaning `r` is now also forced to be dropped, because it does not own the
// string, and would now be a dangling reference. The borrow checker prevents
// dangling references, so this is a compilation error.
println!("{}", r);
}
error[E0505]: cannot move out of `s` because it is borrowed
--> src/main.rs:10:10
|
7 | let r: &String = &s;
| -- borrow of `s` occurs here
...
10 | drop(s);
| ^ move out of `s` occurs here
...
15 | println!("{}", r);
| - borrow later used here
Related
I have this method
async fn insert<'a>(&mut self, params: &'a[&'a dyn QueryParameters<'a>]) {
let mut mapped_fields: String = String::new();
let values: &'a[&'a QueryParameters<'a>] = &[#(#insert_values),*];
// #insert_transaction
}
I would like to know why the compiler and the borrow checker complains about this:
^^^^^^^^^-
| | |
| | temporary value is freed at the end of this statement
| creates a temporary which is freed while still in use
| lifetime `'a` defined here
| type annotation requires that borrow lasts for `'a`
If I just remove the 'a lifetime annotation from the explicit type declaration, everything works. This piece of code is inside a derive proc-macro that it's marked as async-trait, so values is getting 'life0 (if I do not explicitly declare it's lifetime bound as 'a), which is the same as the &mut self.
But, I am confused. I make a new variable (values), as a slice array, but... that variable doesn't goes anywhere. I mean. I am just creating the slice on the let values assignment, but doing anything with it. So, Drop should come at the end of the method and cleaning up the variables for the current stack frame. Fine. But, I am doing nothing with that slice.
Can someone help me to understand better the borrow checker?
You can get a similar error with a simpler code:
fn test<'a>(x: &'a str) {
let p: &'a str = &String::new();
}
That results in:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:2:23
|
1 | fn test<'a>(x: &'a str) {
| -- lifetime `'a` defined here
2 | let p: &'a str = &String::new();
| ------- ^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'a`
3 | }
| - temporary value is freed at the end of this statement
The cause is that the 'a lifetime is a generic argument to the function, that is decided by the caller of that function, and that lifetime will certainly contain the whole execution of the function. For example if calling it with:
let z = String::from("foo");
test(&z);
Then 'a will be the lifetime of that z argument.
Now, when you use that lifetime to annotate a local value such as:
let p: &'a str = &String::new();
or equivalently:
let temp = String::new();
let p: &'a str = &temp;
you are requiring that this reference lives at least as long as 'a. But that is certainly impossible, because temp is a local value, it will never outlive the function itself.
This is precisely what the error is trying to say: you define a lifetime 'a as a generic argument, then you borrow a value that is required to live for 'a because of a type annotation, but that value is dropped sooner than it should be.
Naturally, if you use the argument of the function such as in:
let p: &'a str = &*x;
then all goes well, because *x is explicitly declared to live for 'a.
On the other hand, if you omit the lifetime annotation:
let p: &str = &temp;
then the compiler will just guess the lifetime of temp as a local lifetime and assign that to this reference. And all will go well, too.
I am banging my head trying to figure out Rust's borrowing/lifetime/ownership properties. Namely, when using a buffered reader, and attempting to split a line. The code
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let f = File::open("foo.txt").expect("file not found");
let f = BufReader::new(f);
for line in f.lines() {
let split: Vec<&str> = {
let ln: String = line.unwrap();
ln.split(' ').collect()
};
}
}
or any variation of (with or without specifying variable type, futile attempts to make it mutable, etc) results in:
'ln' does not live long enough; borrowed value must only be valid for the static lifetime...
yet trying to maybe fake an extended lifetime and grab some data out of the line via a slice
let nm = line;
name = &line[..];
or even just trying to operate the split() on the unmodified line variable results in:
cannot index into a value of type 'std::result::Result<std::string::String, std::io::Error>'
"borrowed value does not live long enough" seems to blame the wrong thing suggests that the lifetime lasts long enough to put each word into its own string, but modifying my original code on the Playground to include that nested for loop still results in a
error[E0597]: borrowed value does not live long enough
--> src/main.rs:11:18
|
11 | for w in line.unwrap().split_whitespace() {
| ^^^^^^^^^^^^^ temporary value does not live long enough
...
14 | }
| - temporary value dropped here while still borrowed
15 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
in reference to the line.unwrap()
Ultimately, what am I misunderstanding here about Rust's lifetime or borrowing properties?
The error your original code gives when compiled is:
error[E0597]: `ln` does not live long enough
--> src/main.rs:11:13
|
11 | ln.split(' ').collect()
| ^^ borrowed value does not live long enough
12 | };
| - `ln` dropped here while still borrowed
13 | }
| - borrowed value needs to live until here
error: aborting due to previous error
As per #shepmasters comments it is a good idea to provide the full error when posting a question.
Anyway, it highlights the problem:
let split: Vec<&str> = {
let ln: String = line.unwrap();
ln.split(' ').collect()
};
You are creating a Vec containing references to str slices; slices don't own the data that they are sliced from, they are effectively pointers into data which has to be owned by another variable. Therefore the variable that they are sliced from have to outlive the slices.
Inside the expression you are using to initialise the Vec, you create a String containing the line of text that you are processing. The scope of this string is the variable ln is the initialisation expression - it will be dropped as soon as you leave that scope.
Then you split the string, which returns an iterator to string slices, one per substring. Remember though, the iterator is returning slices, which are pointers to the substrings in the String ln. Those slices are not allowed to outlive ln itself.
Hopefully you can see the problem now. As soon as you exit the initialisation expression, ln is dropped, but the Vec would still contain the str slices. What are they pointing to?
The fix is very simple. Why declare ln inside that block? In fact why have a block there at all? This works:
for line in f.lines() {
let ln: String = line.unwrap();
let split: Vec<&str> = ln.split(' ').collect();
// Now do something with split
}
I have a mutable string variable, and an immutable variable bound to a mutable reference to the mutable string variable.
let mut string = String::from("test");
let variable: &mut String = &mut string;
variable.push_str(" test");
string.push_str(" test");
This fails:
error[E0499]: cannot borrow `string` as mutable more than once at a time
--> src/main.rs:5:5
|
3 | let variable: &mut String = &mut string;
| ------ first mutable borrow occurs here
4 | variable.push_str(" test");
5 | string.push_str(" test");
| ^^^^^^ second mutable borrow occurs here
6 | }
| - first borrow ends here
Without the second variable being mutable, why am I able to call push_str?
Why am I able to call push_str on the second variable and not on the first?
You're getting this error because mutable borrowing is exclusive:
let mut string = String::from("test")
let variable = &mut string;
Here you create a mutable reference to a variable; because mutable references imply exclusive access, it is now impossible to access the original variable, because otherwise you would be violating aliasing guarantees.
Consider this:
let mut string = String::from("test");
{
let variable = &mut string;
variable.push_str(" test");
}
string.push_str(" test");
This code will compile and work as intended, because the mutable reference goes out of scope before the original variable is accessed again.
You can read more about this in the Rust book (see this link for the second edition of the book).
As for why you can call the mutating method on a non-mut variable, well, it is possible simply because the push_str() method accepts its receiver by &mut; if you already have &mut then it is used directly, but if you don't have one, then Rust will automatically try to create one for you, which is not possible if the variable is not mut:
let mut string = String::from("test");
string.push_str("test");
// equivalent to:
String::push_str(&mut string, "test"); // won't work if `string` is not `mut`
let variable = &mut string;
variable.push_str("test");
// [almost] equivalent to:
String::push_str(variable, "test"); // works because `variable` is already `&mut`
I wrote "almost" in the example above because in this case there is another step called reborrowing which basically ensures that the mutable reference can be used again after this call instead of being moved into the function call, but it doesn't really matter for this answer.
The Rust Book explains question 1 pretty well:
let mut x = 5;
let y = &mut x;
y is an immutable binding to a mutable reference, which means that
you can’t bind 'y' to something else (y = &mut z), but y can be
used to bind x to something else (*y = 5).
Basically, variable.push_str(" test"); is mutating the String that variable references, but it does not affect variable (i.e. the binding) itself.
The compiler error should explain question 2.
For reasons related to code organization, I need the compiler to accept the following (simplified) code:
fn f() {
let mut vec = Vec::new();
let a = 0;
vec.push(&a);
let b = 0;
vec.push(&b);
// Use `vec`
}
The compiler complains
error: `a` does not live long enough
--> src/main.rs:8:1
|
4 | vec.push(&a);
| - borrow occurs here
...
8 | }
| ^ `a` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
error: `b` does not live long enough
--> src/main.rs:8:1
|
6 | vec.push(&b);
| - borrow occurs here
7 | // Use `vec`
8 | }
| ^ `b` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
However, I'm having a hard time convincing the compiler to drop the vector before the variables it references. vec.clear() doesn't work, and neither does drop(vec). mem::transmute() doesn't work either (to force vec to be 'static).
The only solution I found was to transmute the reference into &'static _. Is there any other way? Is it even possible to compile this in safe Rust?
Is it even possible to compile this in safe Rust?
No. What you are trying to do is inherently unsafe in the general case.
The collection contains a reference to a variable that will be dropped before the collection itself is dropped. This means that the destructor of the collection has access to references that are no longer valid. The destructor could choose to dereference one of those values, breaking Rust's memory safety guarantees.
note: values in a scope are dropped in the opposite order they are created
As the compiler tells you, you need to reorder your code. You didn't actually say what the limitations are for "reasons related to code organization", but the straight fix is:
fn f() {
let a = 0;
let b = 0;
let mut vec = Vec::new();
vec.push(&a);
vec.push(&b);
}
A less obvious one is:
fn f() {
let a;
let b;
let mut vec = Vec::new();
a = 0;
vec.push(&a);
b = 0;
vec.push(&b);
}
That all being said, once non-lexical lifetimes are enabled, your original code will work! The borrow checker becomes more granular about how long a value needs to live.
But wait; I just said that the collection might access invalid memory if a value inside it is dropped before the collection, and now the compiler is allowing that to happen? What gives?
This is because the standard library pulls a sneaky trick on us. Collections like Vec or HashSet guarantee that they do not access their generic parameters in the destructor. They communicate this to the compiler using the unstable #[may_dangle] feature.
See also:
Moved variable still borrowing after calling `drop`?
"cannot move out of variable because it is borrowed" when rotating variables
I'm learning Rust and tried coding a doubly-linked list. However, I'm stuck already at a typical iterative traversal implementation. I'm getting the impression that the borrow checker / drop checker is too strict and cannot infer the correct lifetime for the borrow when it crosses the function boundary from RefCell. I need to repeatedly set a variable binding (curr in this case) to the borrow of its current contents:
use std::cell::RefCell;
use std::rc::Rc;
pub struct LinkedList<T> {
head: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
struct LinkedNode<T> {
value: T,
next: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
impl<T> LinkedList<T> {
pub fn insert(&mut self, value: T, idx: usize) -> &mut LinkedList<T> {
// ... some logic ...
// This is the traversal that fails to compile.
let mut curr = self.head.as_ref().unwrap();
for _ in 1..idx {
curr = curr.borrow().next.as_ref().unwrap()
}
// I want to use curr here.
// ...
unimplemented!()
}
}
The compiler complains:
Without NLL
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^ temporary value does not live long enough
23 | }
| - temporary value dropped here while still borrowed
...
28 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
With NLL
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^
| |
| creates a temporary which is freed while still in use
| a temporary with access to the borrow is created here ...
23 | }
| -
| |
| temporary value is freed at the end of this statement
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, LinkedNode<T>>`
|
= note: consider using a `let` binding to create a longer lived value
= note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.
I would really appreciate a iterative solution (non-recursive) to this problem.
You can clone Rc to avoid lifetime issues:
let mut curr = self.head.as_ref().unwrap().clone();
for _ in 1..idx {
let t = curr.borrow().next.as_ref().unwrap().clone();
curr = t;
}
Here's a smaller reproduction that I believe shows the same problem:
use std::cell::RefCell;
fn main() {
let foo = RefCell::new(Some(42));
let x = foo.borrow().as_ref().unwrap();
}
As I read it:
foo.borrow() returns a cell::Ref, a type of smart pointer. In this case, the smart pointer acts like an &Option<i32>.
as_ref() creates an Option<&i32> where the inner reference has the same lifetime as the smart pointer.
The Option is discarded, yielding only an &i32, still with a lifetime of the smart pointer.
Notably, the smart pointer Ref only lasts for the statement, but the code attempts to return a reference into the Ref that would outlive the statement.
Generally, the solution would be to do something like this:
let foo_borrow = foo.borrow();
let x = foo_borrow.as_ref().unwrap();
This keeps the smart pointer around longer, allowing the lifetime of the reference to be valid for as long as foo_borrow (representing the borrow itself) exists.
In the case of a loop, there's not much you can do, as you essentially want to borrow every previous node until you get to the next one.