Rust `value borrowed here after move` when setting to Map - rust

I want to put an object in a serde_json::Map where the key will be a value from inside that object.
use serde_json::{json, Map, Value};
fn main() {
let a = json!({
"x": "y"
});
let mut d: Map<String, Value> = Map::new();
d[&a["x"].to_string()] = a;
}
Error:
borrow of moved value: `a`
value borrowed here after moverustcE0382
main.rs(9, 30): value moved here
main.rs(4, 9): move occurs because `a` has type `Value`, which does not implement the `Copy` trait

Even if you solve this lifetime issue, the IndexMut implementation for Map cannot be used for inserting new elements into a map. It panics if the given key is not present.
Use the insert() method instead, which solves both problems:
d.insert(a["x"].to_string(), a);

Since the proper solution has already been answered, I am going to cover another perspective on this,
d[&a["x"].to_string()] = a;
Even if the mentioned bit panics when there is no entry against the passed index, what it is really saying is that, get me the value at index x and replace it with a, = is invoking Copy here, since a doesn't doesn't implement Copy trait the compiler is giving you error.
In the following case, a is simply moved, so no Copy is invoked.
d.insert(a["x"].to_string(), a);
Also, the equivalent in your case may be get or insert.
let entry = d.entry(a["x"].to_string()).or_insert(a);
To access the value from entry you just deref it as *entry

Related

"expected struct `std::rc::Rc`, found reference" - how to convert?

I tried to get a reference-counted Rc<Foo> from a hash map and put it into a different container (Vec<Foo>).
Thought this would work (by incrementing the reference count), but instead I got an "expected struct std::rc::Rc, found reference" error.
How do I convert an &Rc<Foo> to a Rc<Foo>?
More info:
struct Foo();
let mut foo : HashMap<usize, Rc<Foo>> = HashMap::new();
let mut bar : Vec<Rc<Foo>> = Vec::new();
foo.insert(0, Rc::new(Foo()));
if let Some(x) = foo.get(&0) {
bar.push(x); // expected struct `std::rc::Rc`, found reference
// note: expected type `std::rc::Rc<Foo>`
// found type `&std::rc::Rc<Foo>` rustc(E0308)
}
I get that the hash map returns a reference to the value it owns. But dereferencing it doesn't work: both if let Some(&x) and bar.push(*x); result in a "cannot move out of borrowed content".
Curiously, adding a type annotation changes the error to "cannot move out of an Rc":
let x : &Rc<Foo> = x;
bar.push(*x); // cannot move out of an `Rc` rustc(E0507)
I need to store a reference to the same object, and not to a copy, so I avoided the .clone() "escape hatch".
To convert an &Rc<Foo> -> Rc<Foo>, use Rc::clone(), which gives you an Rc object of your own, increasing the reference count under the hood:
let ref_to_rc: &Rc<Foo> = &Rc::new(Foo());
let new_rc: Rc<Foo> = Rc::clone(ref_to_rc);
rc.clone() is equivalent to Rc::clone(&rc), but idiomatic Rust uses the latter to make it clear that the code only increases the refcount, not performing a deep copy of the data like some other implementations of .clone() do. (Though in some scenarios involving traits you might need to revert to ref_to_rc.clone().)
The errors above were about Rust refusing to do the copy implicitly. Why is std::rc::Rc<> not Copy? has an explanation of why it behaves like that.

How can I get a reference to the key and value immediately after inserting into a `HashMap`?

use std::collections::HashMap;
use std::collections::hash_map::Entry::*;
fn hook(k: &str, v: &str) {}
fn tt(k: String, v: String) -> Option<String> {
let mut a: HashMap<String, String> = HashMap::new();
match a.entry(k) {
Occupied(mut occupied) => {
let old = occupied.insert(v);
//hook(&k, &old);
Some(old)
}
Vacant(vacant) => {
let v = vacant.insert(v);
let k = vacant.key(); // Why doesn't it work?
//hook(&k, v);
None
}
}
}
I would like to call hook immediately after a key is inserted into the HashMap. It seems I have to use Entry. However, I am unable to call vacant.key() right after vacant.insert.
TL;DR: You cannot (right now?)
The compiler tells you why it doesn't work. Don't hesitate to read Rust compiler messages; they aren't scary and a lot of effort has gone into them!
error[E0382]: use of moved value: `vacant`
--> src/main.rs:16:21
|
15 | let v = vacant.insert(v);
| ------ value moved here
16 | let k = vacant.key();
| ^^^^^^ value used here after move
|
= note: move occurs because `vacant` has type `std::collections::hash_map::VacantEntry<'_, std::string::String, std::string::String>`, which does not implement the `Copy` trait
This is just normal Rust code. VacantEntry::insert consumes selfby value, returning a reference to the inserted value:
fn insert(self, value: V) -> &'a mut V
There are over 100 other question/answer pairs that ask about this error message, so I'll assume you've read enough of them to understand the problem; that's why we answer questions on Stack Overflow after all!
So why is it this way? That's tougher to answer. When you insert into a HashMap, it takes ownership of the key and the value. When you use the entry API, there's an intermediate step - you've given ownership of the key to the entry. The entry also has a mutable reference to the HashMap; a "bookmark" of where the value is.
When the value is missing and then you insert a value, the key is transferred out of the entry and into the HashMap. This means that the reference to the key inside the entry would be invalidated. That's why you can't reorder the two lines.
However, thinking about it a bit deeper, the value returned from insert refers to the underlying HashMap, after the value has been inserted. I can't see any reason preventing a function from being added that returns a reference to the key and the value. However, such a function doesn't exist now.
See also How can I keep a reference to a key after it has been inserted into a HashMap?
I'm pretty sure in this case you don't need the functionality though.
If you want to call it for the new value, just do all of this before the insertion:
hook(&k, &v);
a.insert(k, v);
If you want to do it only for the old value, doing nothing when there wasn't previously a value, you can:
Occupied(mut occupied) => {
let old = occupied.insert(v);
hook(occupied.key(), &old);
Some(old)
}
If you want to call the hook with the old value if there was one and the new value if inserting (which seems inconsistent), you can call it before adding, the hook function will be none the wiser as the arguments are just references:
Vacant(vacant) => {
hook(vacant.key(), &v);
let v = vacant.insert(v);
None
}

Iterating through a Vec within a struct - cannot move out of borrowed content

I am writing a function for a struct which contains a Vec where I attempt to iterate through the Vec:
struct Object {
pub v: Vec<f32>,
}
impl Object {
pub fn sum(&self) -> f32 {
let mut sum = 0.0;
for e in self.v {
sum += e;
}
sum
}
}
However I get the following error:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:8:18
|
8 | for e in self.v {
| ^^^^ cannot move out of borrowed content
My understanding is that since self is borrowed and that the for loop iteration is attempting to move the elements of v out into e.
From the error code, I read that a potential solution is to take ownership but I'm not quite certain how to do that.
I'm not trying to modify the vector or its elements. I just want to use the elements to run some computation.
The line: for e in self.v is essentially saying for e in (*self).v; you're attempting to iterate over the vector by move, invoking its IntoIterator trait. This would destroy the vector completely, moving all the numbers out of it forever, which is not only not what you want, but also not allowed in this context because you're only allowed to read it.
You actually want to iterate over it by reference. There are two ways to do this:
for e in &self.v {
// ...
}
This is essentially saying &((*self).v), since the . auto-dereferences you need to tell the compiler that you actually just want to borrow the vector.
or
for e in self.v.iter() {
// ...
}
This may look funny because iter takes an &self. Why? Well, the compiler also auto-references if you call a function on a value that takes a reference. This is essentially (&((*self).v)).iter(), but that would suck to write so the compiler helps out.
So why doesn't it auto-reference in the for loop? Well, for x in self.v is a valid statement, and that may be what you intended to write. It's usually more important for the compiler to tell you that what you want want is impossible than assume you wanted something else. With the auto (de-)referencing above, no such ambiguity exists.
The former solution is preferred, but the latter is necessary if you want to use an iterator adapter.
Speaking of which, your sum already exists: just write self.v.iter().sum().

rust: cannot move out of indexed context [duplicate]

This question already has answers here:
What does "cannot move out of index of" mean?
(2 answers)
Closed 6 years ago.
I'm very new to rust, and am starting to get the hang of the ownership system and such, but am still having some hangups. For exmaple, I have the following code:
fn main() {
let mut t = vec![Box::new(4)];
let mut o = t[0];
*o = *o + 1;
t[0] = o;
println!("t[0]:{}", t[0]);
}
Which gives me the cannot move out of indexed content error for the line where I'm initializing o. I understand why this is happening, I think, but I can't figure out what I'm supposed to do instead to accomplish the same thing. This is a very simplified case, but any help would be greatly appreciated. Thanks!
The expression t[0] is equivalent to either *t.index(0) or *t.index_mut(0), based on context. These methods return an immutable reference and a mutable reference, respectively. The indexing operator automatically dereferences these.
Since you have a vector of Box<i32>, dereferencing is not valid, because that would try to move the value from the vector. But then, what do you put in the vector in its place?
Instead of trying to move the value, you need to use a reference to the value instead. Also, if you want to be able to add 1 to the value, you need a reference to the value, not a reference to the Box. You can do this by first dereferencing the box, then by taking a mutable reference to the result:
fn main() {
let mut t = vec![Box::new(4)];
{
let o = &mut *t[0];
*o = *o + 1;
}
println!("t[0]:{}", &t[0]);
}
I had to add a block here to make the mutable borrow end before the println!, otherwise the compiler complained with:
error: cannot borrow `t` as immutable because it is also borrowed as mutable
Also, notice how we don't need to put the updated value back in the vector, because we changed the value in the vector directly by using a reference to it.

Why does the compiler tell me to consider using a `let` binding" when I already am?

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)

Resources