I'm trying to peek at the char in-front of my current location whilst iterating over a &str.
let myStr = "12345";
let mut iter = myStr.chars().peekable();
for c in iter {
let current: char = c;
let next: char = *iter.peek().unwrap_or(&'∅');
}
I will be passing this char into a method down the line. However, even this MRE produces a borrow after move error that I'm not sure how to get past.
error[E0382]: borrow of moved value: `iter`
--> src/lib.rs:7:27
|
4 | let mut iter = myStr.chars().peekable();
| -------- move occurs because `iter` has type `Peekable<Chars<'_>>`, which does not implement the `Copy` trait
5 | for c in iter {
| ---- `iter` moved due to this implicit call to `.into_iter()`
6 | let current: char = c;
7 | let next: char = *iter.peek().unwrap_or(&'∅');
| ^^^^^^^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `iter`
--> /home/james/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:267:18
|
267 | fn into_iter(self) -> Self::IntoIter;
Any idea what's going on here? I've tried various combinations of referencing and dereferencing but nothing I've tried seems to work.
The iterator is moved into the for loop. You cannot manually manipulate an iterator inside a for loop. However, the for loop can be replaced by while let:
while let Some(c) = iter.next() {
let current: char = c;
let next: char = *iter.peek().unwrap_or(&'∅');
}
Playground.
If you can work with slices, it will get much easier with windows():
let slice = ['1', '2', '3', '4', '5'];
let iter = slice.windows(2);
for arr in iter {
let current = arr[0];
let next = arr[1];
}
Playground
Related
I am been working on a program in Rust to read individual lines from a local text file, divide the line into a character vector and do some other operations. This is the snippet of my code:
use std::io::{BufRead, BufReader};
use std::fs::File;
fn main() {
// ----<code snippet>-----
let input_file = File::open("--<text file location>--").unwrap();
let input_file = BufReader::new(input_file);
let mut temp2 = String::new();
let mut counter = 0;
while counter < 12 {
for line in input_file.lines() {
let input_line = line.expect("Failed to read line");
let temp: Vec<char> = input_line.chars().collect::<Vec<_>>();
temp2.push(temp[counter]);
}
//-----<program continues without any issues>-------
Here is the error message as shown up in Cargo:
error[E0382]: use of moved value: `input_file`
--> src\main.rs:48:21
|
42 | let input_file = BufReader::new(input_file);
| ---------- move occurs because `input_file` has type `BufReader<File>`, which does not implement the `Copy` trait
...
48 | for line in input_file.lines() {
| ^^^^^^^^^^ ------- `input_file` moved due to this method call, in previous iteration of loop
|
note: this function takes ownership of the receiver `self`, which moves `input_file`
--> C:\Users\Gumbi\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\std\src\io\mod.rs:2258:14
|
2258 | fn lines(self) -> Lines<Self>
| ^^^^
error[E0382]: borrow of moved value: `temp2`
--> src\main.rs:51:13
|
44 | let mut temp2 = String::new();
| --------- move occurs because `temp2` has type `String`, which does not implement the `Copy` trait
...
51 | temp2.push(temp[counter]);
| ^^^^^ value borrowed here after move
...
54 | let temp3 = most_common_digit(temp2);
| ----- value moved here, in previous iteration of loop
I know the basics of ownership and borrowing, but I am not able to grasp what is the problem in this code. Could anyone please help me in knowing where I am going wrong?
The problem is that input_file is moved inside the while loop scope. Instead use an intermediary &mut that can be dropped in each iteration:
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
// ----<code snippet>-----
let input_file = File::open("--<text file location>--").unwrap();
let mut input_file = BufReader::new(input_file);
let mut temp2 = String::new();
let mut counter = 0;
while counter < 12 {
let mut input_file_ref = &mut input_file;
for line in input_file_ref.lines() {
let input_line = line.expect("Failed to read line");
let temp: Vec<char> = input_line.chars().collect::<Vec<_>>();
temp2.push(temp[counter]);
}
}
}
Playground
This question already has an answer here:
Error while trying to borrow 2 fields from a struct wrapped in RefCell
(1 answer)
Closed 3 years ago.
Trying to get mutable references to separate fields through a MutexGuard:
struct MyObject {
pub a: i32,
pub b: i32,
}
fn func_1(mtx: &Mutex<MyObject>) {
let mut obj = mtx.lock().unwrap();
let a = &mut obj.a;
let b = &mut obj.b;
*a += 1;
*b *= 2;
}
results in an error:
error[E0499]: cannot borrow `obj` as mutable more than once at a time
--> src/main.rs:11:18
|
10 | let a = &mut obj.a;
| --- first mutable borrow occurs here
11 | let b = &mut obj.b;
| ^^^ second mutable borrow occurs here
12 |
13 | *a += 1;
| ------- first borrow later used here
This has me a bit confused. This works when obj is a simple mutable reference (&mut MyObject). I thought maybe the Deref trait was the one causing the problem, but it also works if obj is a &mut Box<MyObject>.
See it on the Rust Playground.
What am I missing?
Mutex::lock returns a RAII lock guard in addition of ways to deal with its contained value. To get its contained value as &mut (and subsequently "split borrow"), you need to:
save the guard (returned by lock) in a separate value, as the lock needs to live as long as the value is accessed.
extract the value as &mut from the guard with MutexGuard::deref_mut.
Here's an updated func_1:
use std::ops::DerefMut;
fn func_1(mtx: &Mutex<MyObject>) {
let mut guard = mtx.lock().unwrap();
let obj = guard.deref_mut();
let a = &mut obj.a;
let b = &mut obj.b;
*a += 1;
*b *= 2;
}
Getting the below error when trying to push more elements to a vector. How to overcome this error
error[E0506]: cannot assign to `x` because it is borrowed
x = format!(r"\*START TIME*{:?}\S*\s+(?P<Value>[a-zA-Z0-9_\-\.]+)", ts);
| ^^ assignment to borrowed `x` occurs here
76 | core_regex_dict.push(&x);
| --------------- --- borrow of `x` occurs here
| |
| borrow later used here
Code:
let mut x = String::new();
for ts in test_list {
x = format!(r"\*START TIME*{:?}\S*\s+(?P<Value>[a-zA-Z0-9_\-\.]+)", ts);
core_regex_dict.push(&x);
}
It's hard to answer your question because you didn't give us enough information. In particular, we need to know how core_regex_dict is defined. I'm assuming that core_regex_dict has type Vec<&str>. You need to change that to Vec<String>:
let core_regex_dict = Vec::new(); // No need to specify the item type, it will be inferred.
// No need to declare `x` before the loop unless you need to use the
// last value afterward...
for ts in test_list {
let x = format!(r"\*START TIME*{:?}\S*\s+(?P<Value>[a-zA-Z0-9_\-\.]+)", ts);
core_regex_dict.push (x); // No `&` -> we push the String itself instead of a reference
}
Found a solution that involves leaking the memory of the String in https://stackoverflow.com/a/30527289/12323498
But, is there a better way to achieve this without leaking the memory?
fn string_to_static_str(s: String) -> &'static str {
Box::leak(s.into_boxed_str())
}
and the code look like this now
let mut s = String::new();
for ts in test_list {
s = format!(r"\*START TIME*{:?}\S*\s+(?P<Value>[a-zA-Z0-9_\-\.]+)", ts);
let s: &'static str = string_to_static_str(s);
core_regex_dict.push(s);
}
I'm trying to read the values from a vector and use the values as indexes to perform an addition:
fn main() {
let objetive = 3126.59;
// 27
let values: Vec<f64> = vec![
2817.42, 2162.17, 3756.57, 2817.42, -2817.42, 946.9, 2817.42, 964.42, 795.43, 3756.57,
139.34, 903.58, -3756.57, 939.14, 828.04, 1120.04, 604.03, 3354.74, 2748.06, 1470.8,
4695.71, 71.11, 2391.48, 331.29, 1214.69, 863.52, 7810.01,
];
let values_number = values.len();
let values_index_max = values_number - 1;
let mut additions: Vec<usize> = vec![0];
println!("{:?}", values_number);
while additions.len() > 0 {
let mut addition: f64 = 0.0;
let mut saltar: i32 = 0;
// Sumar valores en additions
for element_index in additions {
let addition_aux = values[element_index];
addition = addition_aux + addition;
}
}
}
I get the following error. How can I solve it?
error[E0382]: use of moved value: `additions`
--> src/main.rs:18:11
|
18 | while additions.len() > 0 {
| ^^^^^^^^^ value used here after move
...
23 | for element_index in additions {
| --------- value moved here
|
= note: move occurs because `additions` has type `std::vec::Vec<usize>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `additions`
--> src/main.rs:23:30
|
23 | for element_index in additions {
| ^^^^^^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `additions` has type `std::vec::Vec<usize>`, which does not implement the `Copy` trait
The fix for this particular problem is to borrow the Vec you're iterating over instead of moving it:
for element_index in &additions {
let addition_aux = values[*element_index];
addition = addition_aux + addition;
}
but your code has other problems. You never change additions by adding or removing elements, so your while additions.len() > 0 will never terminate. I hope this is because you haven't finished and wanted to work out how to fix the immediate problem before writing the rest of the function.
For now, you might benefit from re-reading the chapter of the Rust Book about ownership, moves, and borrowing.
How can I get a mutable reference to an item found in a vector?
I've tried the following which works if I don't make the iterator mutable using .iter():
fn main() {
let mut vec = vec![1, 2, 3, 4];
let mut wrong = -1;
let working = match vec.iter().find(|&c| *c == 2) {
Some(c) => c,
None => &wrong
};
println!("Result: {}", working);
}
But when I try to get a mutable reference using a mutable iterator .iter_mut(),
fn main() {
let mut vec = vec![1, 2, 3, 4];
let mut wrong = -1;
let mut error = match vec.iter_mut().find(|&c| *c == 2) {
Some(c) => c,
None => &mut wrong
};
println!("Result: {}", error);
}
I get the following error:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:5:48
|
5 | let mut error = match vec.iter_mut().find(|&c| *c == 2) {
| ^-
| ||
| |hint: to prevent move, use `ref c` or `ref mut c`
| cannot move out of borrowed content
I also tried to make the type in the closure mutable with |&mut c| but that gives the following error:
error[E0308]: mismatched types
--> src/main.rs:5:48
|
5 | let mut error = match vec.iter_mut().find(|&mut c| *c == 2) {
| ^^^^^^ types differ in mutability
|
= note: expected type `&&mut {integer}`
found type `&mut _`
= help: did you mean `mut c: &&&mut {integer}`?
Rust's .find passes the callback the type &Self::Item, and since you are using .iter_mut(), you've created an iterator where each item is &mut T. That means the type passed to your find callback is &&mut T. To get that to typecheck, you can do either
vec.iter_mut().find(|&&mut c| c == 2)
or
vec.iter_mut().find(|c| **c == 2)
with the second one being preferable.
The error you are getting is because the middle-ground you've chosen by using &c would set c to a value of &mut T, and one of Rust's big rules is that multiple things can't own a mutable reference to an item at the same time. Your non-mutable case works because you are allowed to have multiple immutable references to an item.