Why does serde::json need to copy this ref? [duplicate] - rust

This question already has an answer here:
Can I pass the same mutable trait object in multiple iterations of a loop without adding indirection?
(1 answer)
Closed 25 days ago.
Here's some simple code that seems like it should work:
use serde_json;
use std::io::Write;
fn test(writer: &mut dyn Write) {
serde_json::to_writer(writer, "test1").unwrap();
serde_json::to_writer(writer, "test2").unwrap();
}
But it produces the following error:
error[E0382]: use of moved value: `writer`
--> src/main.rs:35:27
|
33 | fn test(writer: &mut dyn Write) {
| ------ move occurs because `writer` has type `&mut dyn std::io::Write`, which does not implement the `Copy` trait
34 | serde_json::to_writer(writer, "test1").unwrap();
| ------ value moved here
35 | serde_json::to_writer(writer, "test2").unwrap();
| ^^^^^^ value used here after move
To get it to work, I have to jump through this hoop:
fn test(writer: &mut dyn Write) {
serde_json::to_writer(&mut *writer, "test1").unwrap();
serde_json::to_writer(writer, "test2").unwrap();
}
What is going on here? Why can I "manually" copy the ref by deref/re-referencing it, but it doesn't implement Copy?
This is specifically something to do with the generic type signature of serde_json::to_writer, because it also works fine with a different function:
fn test(x: &mut dyn Write) {
x.write_all(b"test1").unwrap();
x.write_all(b"test2").unwrap();
}

In Rust &T implements Copy. However, &mut T doesn't. It has to be moved (because of Aliasing NAND Mutability)
In your case writer being a &mut T is moved out into serde_json::to_writer and afterwards the reference is unusable for another call. However, for convenience Rust allows to borrow mutably from a mutable refenrence in simple cases - only if this borrow will die before the original mutable reference is used. This is what you did in your quesion, you may consider it as a "temporary reversable ownership transfer"
Trying to use it in other ways would fail. For example, this one uses the original mutable reference before the the secondary borrow is eliminated.
fn test(writer: &mut dyn Write) {
let mut w = &mut *writer;
serde_json::to_writer(writer, "test1").unwrap();
serde_json::to_writer(w, "test1").unwrap();
}
error[E0505]: cannot move out of `writer` because it is borrowed
--> src/main.rs:6:27
|
5 | let mut w = &mut *writer;
| ------------ borrow of `*writer` occurs here
6 | serde_json::to_writer(writer, "test1").unwrap();
| ^^^^^^ move out of `writer` occurs here
7 | serde_json::to_writer(w, "test1").unwrap();
| - borrow later used here
And this one tries to create multiple temprorary mutable borrows at the same time
fn test(writer: &mut dyn Write) {
let mut w = &mut *writer;
let mut w1 = &mut *writer;
serde_json::to_writer(w, "test1").unwrap();
}
error[E0499]: cannot borrow `*writer` as mutable more than once at a time
--> src/main.rs:6:18
|
5 | let mut w = &mut *writer;
| ------------ first mutable borrow occurs here
6 | let mut w1 = &mut *writer;
| ^^^^^^^^^^^^ second mutable borrow occurs here
7 | serde_json::to_writer(w, "test1").unwrap();
| - first borrow later used here

Related

Borrow of moved value error, but the value shouldn't have moved, because it's borrowed [duplicate]

This question already has answers here:
Iterate through a mutable reference of vector without moving the value from the vector
(2 answers)
Move error in for-loop when not reborrowing a mutable slice
(1 answer)
Do mutable references have move semantics?
(1 answer)
Closed 3 months ago.
I'm trying to make sense of the error that comes up, it says that I can't borrow a moved value, but the value is the borrowed value nurse_list: &mut Vec<Nurse>. So when I use it in the code for nurse in nurse_list { ... } it shouldn't move there, it should be borrowed.
fn assign_nurses_to_schedule(
nurse_list: &mut Vec<Nurse>,
fte_budget: &Vec<NursesNeeded>,
cyclical_rosters: &Vec<Roster>,
total_incumbent_score: &mut i32,
) -> Vec<Assignment> {
let mut assignments: Vec<Assignment> = vec![];
let mut incumbent_score = 1000;
//let mut total_incumbent_score = 0;
let mut new_score: i32;
for schedule in cyclical_rosters {
let mut taken_nurse: Option<i32> = None;
for nurse in nurse_list {
new_score = calculate_score(&schedule, nurse.get_pref_score().to_vec());
if incumbent_score < new_score {
incumbent_score = new_score;
assignments.push(new_assignment(schedule.get_nr(), nurse.get_nr()));
taken_nurse = Some(nurse.get_nr());
}
}
//add preference penalty to total score
*total_incumbent_score += incumbent_score;
//remove the nurse from the list, already assigned to a schedule
let index = nurse_list
.iter()
.position(|x| x.get_nr() == taken_nurse.unwrap());
nurse_list.remove(index.unwrap());
// TODO: stop assigning nurses to schedules when fte budget is reached
// ? do the schedules adhere to the fte budget?
}
assignments
}
error[E0382]: borrow of moved value: `nurse_list`
--> src\main.rs:75:21
|
53 | nurse_list: &mut Vec<Nurse>,
| ---------- move occurs because `nurse_list` has type `&mut Vec<definitions::Nurse>`, which does not implement the `Copy` trait
...
64 | for nurse in nurse_list {
| ---------- `nurse_list` moved due to this implicit call to `.into_iter()`
...
75 | let index = nurse_list
| _____________________^
76 | | .iter()
| |___________________^ value borrowed here after move
|
= note: borrow occurs due to deref coercion to `[definitions::Nurse]`
I tried borrowing the nurse_list again in the for loop for nurse in &nurse_list { ... } which then returns the following error:
src\main.rs:64:22
|
64 | for nurse in &nurse_list {
| ^^^^^^^^^^^ `&&mut Vec<definitions::Nurse>` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&&mut Vec<definitions::Nurse>`
The type &mut T which is a reference doesn't implement Copy thus the reference moved in the first loop and you can't access it anymore. To get around this you have to reborrow with this:
for nurse in &mut *nurse_list {…}
in every loop you do not want the nurse_list to move into.

Access variable after it was borrowed

I am assigning data to properties of a struct, but the following error appears:
error[E0382]: borrow of partially moved value: `super_hero`
--> src/main.rs:16:22
|
13 | for mut chunk in super_hero.description_chunks.unwrap() {
| -------- `super_hero.description_chunks` partially moved due to this method call
...
16 | println!("{:?}", &super_hero);
| ^^^^^^^ value borrowed here after partial move
|
note: this function takes ownership of the receiver `self`, which moves `super_hero.description_chunks`
--> /Users/someuser/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:752:25
|
752 | pub const fn unwrap(self) -> T {
| ^^^^
= note: partial move occurs because `super_hero.description_chunks` has type `std::option::Option<Vec<Chunk>>`, which does not implement the `Copy` trait
help: consider calling `.as_ref()` to borrow the type's contents
|
13 | for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
The following is the code where I am assigning data to properties of a struct:
let super_hero_description = "several years ago.";
let mut super_hero = SuperHero::new(super_hero_description);
super_hero.description_chunks = Option::from(super_hero.get_decription_chunks(DescriptionTypes::NotVillan));
for mut chunk in super_hero.description_chunks.unwrap() {
chunk.data = Option::from(chunk.get_data(DescriptionTypes::NotVillan).await);
}
println!("{:?}", &super_hero);
The error does not happen until I try to print the super_hero at the end.
Oh, and if I follow the recommendation rust gives me
for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
I end up with another error:
error[E0594]: cannot assign to `chunk.data`, which is behind a `&` reference
--> src/main.rs:14:9
|
13 | for mut subdivision in super_hero.description_chunks.as_ref().unwrap() {
| ------------------------------------- this iterator yields `&` references
14 | chunk.data = Option::from(chunk.get_data()(DescriptionTypes::NotVillan).await);
| ^^^^^^^^^^^^ `chunk` is a `&` reference, so the data it refers to cannot be written
rustc is correct, it just needs a little adjustment: instead of as_ref() use as_mut(), that converts &mut Option<T> to Option<&mut T> instead of &Option<T> to Option<&T>.
The problem is that unwrap() requires an owned Option: see Reference to unwrapped property fails: use of partially moved value: `self`.

Borrow Checker: Cannot borrow as immutable because it is also borrowed as mutable

I'm having trouble with the borrow checker not "releasing" a mutable borrow.
I have:
let mut data = (1..=100).collect::<Vec<_>>();
let mut c = Canvas::new(10, 10, &mut data);
c.iter_rows_mut(4..7);
c.iter_rows(4..7).collect::<Vec<_>>();
And it's complaining:
error[E0502]: cannot borrow `c` as immutable because it is also borrowed as mutable
--> src/lib.rs:59:9
|
57 | c.iter_rows_mut(4..7);
| - mutable borrow occurs here
58 |
59 | c.iter_rows(4..7).collect::<Vec<_>>();
| ^
| |
| immutable borrow occurs here
| mutable borrow later used here
error: aborting due to previous error
I can understand the problem if I was handing onto a reference related to the mutable call, but that doesn't appear to be the case.
Rust Playground with full code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=de4143ddf57cc8a97e7a884bbe13dfa4
The problem here is in the lifetime annotations. You're using the same lifetime 'd throughout, so the mutable borrow in c.iter_rows_mut has to last the entire lifetime of c.
To fix this, use a different lifetime in iter_rows and iter_rows_mut. It'll be implicitly bound to be no longer than 'd, but it'll allow more flexibility.
The fully explicit signatures should be
fn iter_rows<'a>(&'a self, vertical_range: Range<usize>) -> impl Iterator<Item=(usize, &'a [T])> + 'a
and
fn iter_rows_mut<'a>(&'a mut self, vertical_range: Range<usize>) -> impl Iterator<Item=(usize, &'a mut [T])> + 'a {
Thanks to lifetime elision, though, we don't need any of those lifetimes. All the lifetimes in the output type will be implicitly the same as the lifetime on &self (or &mut self).
fn iter_rows(&self, vertical_range: Range<usize>) -> impl Iterator<Item=(usize, &[T])>
fn iter_rows_mut(&mut self, vertical_range: Range<usize>) -> impl Iterator<Item=(usize, &mut [T])>
(playground)
P.S. The into_iter calls in each of these functions aren't necessary: chunks_exact already produces an iterator. Clippy warns about this.

How can I give names to Rust slices without taking ownership?

In the context of a crypto problem, to decrease verbosity, I'm "naming" a slice of v as block, doing some stuff to it, but then trying to verify the result of do_stuff on the whole of v:
fn x() {
let mut v = vec![0; 32];
let block = &mut v[0..16];
do_stuff(block);
check_stuff(&v);
do_stuff(block);
}
fn do_stuff(_: &mut [i32]) {}
fn check_stuff(_: &[i32]) {}
The borrow checker complains:
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/lib.rs:6:17
|
3 | let block = &mut v[0..16];
| - mutable borrow occurs here
...
6 | check_stuff(&v);
| ^^ immutable borrow occurs here
7 | do_stuff(block);
| ----- mutable borrow later used here
I'm aware of the kind of guarantee this is trying to provide. However, assuming I know what I'm doing, is there an idiomatic way to give a name to the slice without having to use do_stuff(&mut v[0..16]) or having to make copies every time?

Is there a way to get a reference to a mutable sub-slice of a Vec<T>?

I want to preallocate a vector and then write into slices of it, including writing to it from a TcpStream , which takes a buf: &mut [u8] as an argument.
// Create a vec with 256MB capacity
let mut myvec: Vec<u8> = Vec::with_capacity(268435456);
// Grow the vec to 256MB and initialize it with zeroes
myvec.resize(268435456, 0x00);
// Try to get a mutable slice of the first 1kb of the vec
let body_slice: &mut [u8] = myvec[10..1034];
error[E0308]: mismatched types
--> src/lib.rs:9:33
|
9 | let body_slice: &mut [u8] = myvec[10..1034];
| --------- ^^^^^^^^^^^^^^^
| | |
| | expected `&mut [u8]`, found slice `[u8]`
| | help: consider mutably borrowing here: `&mut myvec[10..1034]`
| expected due to this
You want this:
let body_slice: &mut [u8] = &mut myvec[10..1034];

Resources