I'm reading through the Rust documentation on lifetimes. I tried something like:
struct S {
x: i8,
}
impl S {
fn fun(self) {}
fn print(&self) {
println!("{}", self.x);
}
}
fn main() {
let s = S { x: 1 };
s.fun();
s.print();
}
I get the following error:
error[E0382]: borrow of moved value: `s`
--> src/main.rs:16:5
|
15 | s.fun();
| - value moved here
16 | s.print();
| ^ value borrowed here after move
|
= note: move occurs because `s` has type `S`, which does not implement the `Copy` trait
This is because the fun(self) method takes ownership of the s instance. This is solved by changing to fun(&self).
I can't see why you would ever want to have a method on an object take control of itself. I can think of only one example, a destructor method, but if you wanted to do dispose of the object then it would be taken care of by the owner of the object anyway (i.e. scope of main in this example).
Why is it possible to write a method that takes ownership of the struct? Is there ever any circumstance where you would want this?
The idiomatic way to refer to a method that "takes control" of self in the Rust standard library documentation is to say that it "consumes" it. If you search for this, you should find some examples:
Option::unwrap_or_default
A lot in the Iterator trait.
As to why: you can try rewriting Iterator::map — you would end up having a lifetime parameter wandering around that would quickly become unmanageable. Why? Because the Map iterator is based upon the previous one, so the borrow checker will enforce that you can only use one of the two at the same time.
Conversion from type A to type B commonly involves functions taking self by value. See the implementors of Into and From traits for concrete examples.
Related
I have the following code which you can also see in the playground:
struct Node<'a> {
parent: Option<&'a Node<'a>>,
name: &'a str,
}
fn looper(nodes: &mut Vec<Node>) {
for i in 0..nodes.len() {
let n = &nodes[i];
let next_node = Node {
parent: Some(n),
name: "please compile",
};
nodes.push(next_node);
}
}
It's supposed to take a Vec of Nodes and append Nodes to it that reference the Nodes already in the Vec. Unfortunately I get this error:
error[E0623]: lifetime mismatch
--> src/main.rs:13:20
|
6 | fn looper(nodes: &mut Vec<Node>) {
| -------------- these two types are declared with different lifetimes...
...
13 | nodes.push(next_node);
| ^^^^^^^^^ ...but data from `nodes` flows into `nodes` here
How can I make this compile? An explanation of how to think about lifetimes in this context would be useful. I understand this may be an issue due to variance but am not sure how to rephrase my problem to give me the functionality I would like.
A general rule: when some value's type, or trait it implements, has a lifetime parameter, that lifetime is always longer than the life of the value itself — the value has a guarantee that the references it contains won't go invalid before they are dropped.
In fact, in your example we can see that if this were not the case, the lifetime checking would be unsound; you're adding values to nodes, but nothing would prevent looper from instead removing values from nodes, which would then invalidate any parent references that referred to those values.
The only practical way to build a tree or linked list of references (without special-purpose unsafe code that has a particular plan to keep things sound) is to write a recursive function; each function call frame may refer to nodes constructed by its caller (and its caller's caller and so on). This is accepted by the borrow checker because each frame has its own new, shorter lifetime for the references (a reference can always be taken as having a shorter lifetime than it started with).
This question already has an answer here:
Cannot borrow as immutable because it is also borrowed as mutable in function arguments
(1 answer)
Closed 4 years ago.
When a mutable argument is passed as a function argument, the borrow checker doesn't allow this to be used to construct other arguments, even when those arguments clone values without holding a reference.
While assigning variables outside the function is always an option1, logically this seems over zealous and something the borrow checker could take into account.
Is this working as intended or something that should be resolved?
#[derive(Debug)]
struct SomeTest {
pub some_value: f64,
pub some_other: i64,
}
fn some_fn(var: &mut SomeTest, other: i64) {
println!("{:?}, {}", var, other);
}
fn main() {
let mut v = SomeTest { some_value: 1.0, some_other: 2 };
some_fn(&mut v, v.some_other + 1);
// However this works!
/*
{
let x = v.some_other + 1;
some_fn(&mut v, x);
}
*/
}
Gives this error:
--> src/main.rs:14:21
|
14 | some_fn(&mut v, v.some_other + 1);
| - ^^^^^^^^^^^^ use of borrowed `v`
| |
| borrow of `v` occurs here
See: playpen.
[1]: Even though one-off assignments do sometimes improve readability, being forced to use them for arguments encourages use of scopes to avoid single use variables polluting the name-space, causing function calls that would otherwise be one line - being enclosed in braces and defining variables... I'd like to avoid this if possible especially when the requirement seems like something the borrow checker could support.
This is an artifact of the current implementation of the borrow checker. It is a well known limitation, dating back to at least 2013, and no one is overjoyed by it.
Is this working as intended
Yes.
something that should be resolved?
Yes.
The magic keywords are "non-lexical lifetimes". Right now, lifetimes are lexical - they correspond to the blocks of source that we type. Ideally, foo.method(foo.mutable_method()) would see that the borrow ends "inside the parenthesis", but for a myriad of reasons, it is tied to the entire statement.
For tons of further information see RFC issue 811 and everything linked from there.
This simple program:
fn main() {
let b: Box<i32> = Box::new(1);
b.into_raw();
}
Produces this inconvenient error when compiled with Rust 1.12.0:
error: no method named `into_raw` found for type `Box<i32>` in the current scope
--> <anon>:3:7
|
3 | b.into_raw();
| ^^^^^^^^
|
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
= note: candidate #1 is defined in an impl for the type `Box<_>`
This is because into_raw is not defined to take self as parameter, but instead is defined as:
impl Box<T: ?Sized> {
fn into_raw(b: Box<T>) -> *mut T;
}
This seems inconvenient, and I cannot find a rationale.
So... why?
Because 99.995% of the time (statistic totally made up), you expect method calls to happen to the thing being pointed to, not to the pointer itself. As a result, the "smart pointer" types in Rust generally avoid doing anything to break that expectation. An obvious exception would be something like Rc/Arc implementing Clone directly.
Box implements Deref, which means that all methods that are enclosed by the Box are automatically made available; from the outside, Box<T> and T look and act the same.
If into_raw were a method instead of an associated function, it would shadow any into_raw method on the contained type.
There are other examples of these enhancing associated functions on Rc, such as downgrade or try_unwrap, or on Arc, such as make_mut.
What is my error and how to fix it?
fn get_m() -> Vec<i8> {
vec![1, 2, 3]
}
fn main() {
let mut vals = get_m().iter().peekable();
println!("Saw a {:?}", vals.peek());
}
(playground)
The compiler's error suggests "consider using a let binding" — but I already am:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:6:45
|
6 | let mut vals = get_m().iter().peekable();
| ------- ^ temporary value dropped here while still borrowed
| |
| temporary value created here
7 | println!("Saw a {:?}", vals.peek());
8 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
This is obviously a newbie question -- though I thought I'd written enough Rust at this point that I had a handle on the borrow checker... apparently I haven't.
This question is similar to Using a `let` binding to increase value lifetime, but doesn't involve breaking down an expression into multiple statements, so I don't think the problem is identical.
The problem is that the Peekable iterator lives to the end of the function, but it holds a reference to the vector returned by get_m, which only lasts as long as the statement containing that call.
There are actually a lot of things going on here, so let's take it step by step:
get_m allocates and returns a vector, of type Vec<i8>.
We make the call .iter(). Surprisingly, Vec<i8> has no iter method, nor does it implement any trait that has one. So there are three sub-steps here:
Any method call checks whether its self value implements the Deref trait, and applies it if necessary. Vec<i8> does implement Deref, so we implicitly call its deref method. However, deref takes its self argument by reference, which means that get_m() is now an rvalue appearing in an lvalue context. In this situation, Rust creates a temporary to hold the value, and passes a reference to that. (Keep an eye on this temporary!)
We call deref, yielding a slice of type &[i8] borrowing the vector's elements.
This slice implements the SliceExt trait, which does have an iter method. Finally! This iter also takes its self argument by reference, and returns a std::slice::Iter holding a reference to the slice.
We make the call .peekable(). As before, std::slice::Iter has no peekable method, but it does implement Iterator; IteratorExt is implemented for every Iterator; and IteratorExt does have a peekable method. This takes its self by value, so the Iter is consumed, and we get a std::iter::Peekable back in return, again holding a reference to the slice.
This Peekable is then bound to the variable vals, which lives to the end of the function.
The temporary holding the original Vec<i8>, to whose elements the Peekable refers, now dies. Oops. This is the borrowed value not living long enough.
But the temporary dies there only because that's the rule for temporaries. If we give it a name, then it lasts as long as its name is in scope:
let vec = get_m();
let mut peekable = vec.iter().peekable();
println!("Saw a {:?}", vals.peek());
I think that's the story. What still confuses me, though, is why that temporary doesn't live longer, even without a name. The Rust reference says, "A temporary's lifetime equals the largest lifetime of any reference that points to it." But that's clearly not the case here.
This is happening because you are trying to run your .iter().peekable() on the actual vector inside of get_m(), which is getting re-referenced by vals.
Basically, you want something like this:
fn get_m() -> Vec<i8> {
vec![1, 2, 3]
}
fn main() {
let vals = get_m();
let mut val = vals.iter().peekable();
println!("Saw a {:?}", val.peek());
}
(Playground)
Result:
Saw a Some(1)
I defined an Attribute type and I have a Vec<Attribute> that I am looping over to retrieve the "best" one. This was similar to my first attempt:
#[derive(Debug)]
struct Attribute;
impl Attribute {
fn new() -> Self {
Self
}
}
fn example(attrs: Vec<Attribute>, root: &mut Attribute) {
let mut best_attr = &Attribute::new();
for a in attrs.iter() {
if is_best(a) {
best_attr = a;
}
}
*root = *best_attr;
}
// simplified for example
fn is_best(_: &Attribute) -> bool {
true
}
I had the following compile error:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:17:13
|
17 | *root = *best_attr;
| ^^^^^^^^^^ cannot move out of borrowed content
After some searching for a solution, I resolved the error by doing the following:
Adding a #[derive(Clone)] attribute to my Attribute struct
Replacing the final statement with *root = best_attr.clone();
I don't fully understand why this works, and I feel like this is a rough solution to the problem I was having. How does this resolve the error, and is this the correct way to solve this problem?
You are experiencing the basis of the Rust memory model:
every object can (and must!) be owned by only exactly one other object
most types are never implicitly copied and always moved (there are some exceptions: types that implement Copy)
Take this code for example:
let x = String::new();
let y = x;
println!("{}", x);
it generates the error:
error[E0382]: borrow of moved value: `x`
--> src/main.rs:4:20
|
3 | let y = x;
| - value moved here
4 | println!("{}", x);
| ^ value borrowed here after move
|
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
x, of type String, is not implicitly copyable, and thus has been moved into y. x cannot be used any longer.
In your code, when you write *root = *best_attr, you are first dereferencing the reference best_attr, then assigning the dereferenced value to *root. Your Attribute type is not Copy, thus this assignment should be a move.
Then, the compiler complains:
cannot move out of borrowed content
Indeed, best_attr is an immutable reference, which does not allow you to take ownership of the value behind it (it doesn't even allow modifying it). Allowing such a move would put the object owning the value behind the reference in an undefined state, which is exactly what Rust aims to prevent.
In this case, your best option is indeed to create a new object with the same value as the first one, which is exactly what the trait Clone is made for.
#[derive(Clone)] allows you to mark your structs as Clone-able, as long as all of their fields are Clone. In more complex cases, you'll have to implement the trait by hand.