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);
}
Related
What I am trying to do
I have in iterator returned from std::str::SplitWhitespace, I need the first element, and a vector of all elements.
What I have tried
I tried to use peek. However this seems to need a mutable (I can't we why), and I end up with borrowing errors.
Simplified code, with compile errors.
fn main(){
let line = "hello, world";
let mut tokens = line.split_whitespace().peekable();
if let Some(first) = tokens.peek() {
//println!("{first}"); //works
//println!("{tokens:?}"); // works
println!("{first}\n{tokens:?}"); //compile error
}
}
error[E0502]: cannot borrow `tokens` as immutable because it is also borrowed as mutable
--> src/main.rs:7:29
|
4 | if let Some(first) = tokens.peek() {
| ------------- mutable borrow occurs here
...
7 | println!("{first}\n{tokens:?}"); //error
| --------------------^^^^^^-----
| | |
| | immutable borrow occurs here
| mutable borrow later used here
If I un-comment the two printlns, and comment the erroneous one. then It works. This lead me to adding a clone let first = first.clone();, before the printlns. This fixed it, but I am wondering if there is a better way.
The simplest way to achieve this is to just collect the vector, then get the first element:
let tokens: Vec<_> = line.split_whitespace().collect();
if let Some(first) = tokens.first() {
println!("{first}\n{tokens:?}");
}
Note the type of tokens will be Vec<&str> -- a vector of string slices that are borrowed from line. If you instead want a vector of owned strings (Vec<String>), then you need to map each element to an owned string:
let tokens: Vec<_> = line.split_whitespace().map(|s| s.to_owned()).collect();
struct C {
p: String,
q: String,
}
impl C {
fn call(&mut self) {}
}
fn main(){
let mut c = C { p: "p".to_string(), q: "q".to_string() };
let r_c = &mut c;
let p = &mut r_c.p;
let q = &mut r_c.q; // ???
r_c.call();
p.push('x');
q.push('y');
}
Fails with (playground)
error[E0499]: cannot borrow `*r_c` as mutable more than once at a time
--> src/main.rs:15:9
|
13 | let p = &mut r_c.p;
| ---------- first mutable borrow occurs here
14 | let q = &mut r_c.q; // ???
15 | r_c.call();
| ^^^^^^^^^^ second mutable borrow occurs here
16 | p.push('x');
| ----------- first borrow later used here
I know how to fix error[E0499]. I just don't understand that
mutable borrow occurs in let p = &mut r_c.p;, but why does mutable borrow not occur in let q = &mut r_c.q;?
let p = &mut r_c.p; // --------------------------+borrow `*r_c` first
let q = &mut r_c.q; // ----+borrow `*r_c` second |
// | |
p.push('x'); // ----|---------------------+
q.push('y'); // ----+
if mutable borrow occurs in let q = &mut r_c.q;, the code above should be error. But in fact, the code above compiles.
The first borrow p is enough to be in conflict with the usage of r_c.
No need to repeat the same diagnostic with q.
If you swap these two lines, you have the same message about q.
If you reorder this way
let r_c = &mut c;
r_c.call();
let p = &mut r_c.p;
let q = &mut r_c.q; // ???
p.push('x');
q.push('y');
these conflicts disappear since r_c is not used anymore after .call().
These exclusive references don't really hurt as long as you don't use them; i.e. pass them to functions.
I guess you introduced these references for an experimentation purpose (good thing), but in practice we should try to avoid letting them span over long portions of code (between their creation and their last usage) because conflicts with other operations may occur in the middle.
From the edited question:
but why does mutable borrow not occur in let q = &mut r_c.q;?
It does occur.
The error is on r_c.call() and the message shows the first reference (p) causing this error; the message is first mutable borrow occurs here.
Even if the second reference (q) did not exist, the error would be the same.
If twelve references were taken here, the error would still be the same; no need to repeat the same help message many times.
I have trouble solving an obvious simple problem.
Basically I want to push an instance of a structure to a vector to get it out later and to modify the object by calling a function implemented for the structure.
To simplify the case, I created the following test code, which reflects in my opinion to the same problem.
let mut strings = Vec::new();
strings.push("Hello".to_string());
let string_option = strings.last();
let string = string_option.unwrap();
string.shrink_to(1);
This has the compile error
error[E0596]: cannot borrow `*string` as mutable, as it is behind a `&` reference
--> src/main.rs:89:5
|
88 | let string = string_option.unwrap();
| ------ help: consider changing this to be a mutable reference: `&mut String`
89 | string.shrink_to(1);
| ^^^^^^^^^^^^^^^^^^^ `string` is a `&` reference, so the data it refers to cannot be borrowed as mutable
Then I tried sheer endless variants like
let mut strings = Vec::new();
strings.push("Hello".to_string());
let string_option = strings.last().as_mut();
let string = string_option.unwrap();
string.shrink_to(1);
... or ...
let mut strings = Vec::new();
strings.push("Hello".to_string());
let string_option = strings.last().as_deref_mut();
let string = string_option.unwrap();
string.shrink_to(1);
Actually the code shown above is a simplification from this code, which I originally wanted to do.
struct Bar {
data: Vec<String>
}
impl Bar {
fn shrink_first(&mut self) {
let s_opt = self.data.last().as_mut(); // s_opt is of type Option<&mut &String>
let s = s_opt.unwrap(); // s is of type &mut & String
s.shrink_to(1);
}
}
The code above brings the following errors ...
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:67:21
|
67 | let s_opt = self.data.last().as_mut(); // s_opt is of type Option<&mut &String>
| ^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
68 |
69 | let s = s_opt.unwrap(); // s is of type &mut & String
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error[E0596]: cannot borrow `**s` as mutable, as it is behind a `&` reference
--> src/main.rs:70:9
|
70 | s.shrink_to(1);
| ^^^^^^^^^^^^^^ cannot borrow as mutable
But in my opinion it always has the same root causes, but I have not figured out what to do.
Simply change strings.last() to strings.last_mut().
The last() method returns a standard (immutable) reference (to be more precise, Option<&T>).
To be able to mutate the last String in the vector, you need to get a mutable reference via last_mut().
This question already has answers here:
How can I borrow from a HashMap to read and write at the same time?
(2 answers)
Closed 2 years ago.
I want move elements of HashSet[0] to HashSet[1], but always encounter borrowed error:
I try using a tmp vec to save the elemetns, but problem still exists:
use std::collections::HashSet;
fn main() {
let mut hsets = vec![];
hsets.push(HashSet::new());
hsets[0].insert("a1");
hsets[0].insert("a2");
hsets.push(HashSet::new());
hsets[1].insert("b1");
hsets[1].insert("b2");
// tmp vec save hsets[0]: [a1, a2]
let mut arr = vec![];
for v in &hsets[0] {
arr.push(v);
}
for v2 in arr {
hsets[1].insert(v2);
}
}
Result:
error[E0502]: cannot borrow `hsets` as mutable because it is also borrowed as immutable
--> src/main.rs:18:9
|
13 | for v in &hsets[0] {
| ----- immutable borrow occurs here
...
17 | for v2 in arr {
| --- immutable borrow later used here
18 | hsets[1].insert(v2);
| ^^^^^ mutable borrow occurs here
error: aborting due to previous error
I'm assuming you don't want to move the HashSets out of the Vec or de-allocate them, in which case you can do this:
use std::collections::HashSet;
fn main() {
let mut hsets = vec![];
// first set
hsets.push(HashSet::new());
hsets[0].insert("a1");
hsets[0].insert("a2");
// second set
hsets.push(HashSet::new());
hsets[1].insert("b1");
hsets[1].insert("b2");
dbg!(&hsets);
assert_eq!(hsets[0].len(), 2);
assert_eq!(hsets[1].len(), 2);
// move elements from first set to second set
let (first, second) = hsets.split_at_mut(1);
second[0].extend(first[0].drain());
dbg!(&hsets);
assert_eq!(hsets[0].len(), 0);
assert_eq!(hsets[1].len(), 4);
}
playground
If you'd like to get a deeper understanding of why your code as-is doesn't compile then read How to get mutable references to two array elements at the same time?.
Try to be explicit about the type of the Vector like
let mut arr: Vec<&str> = vec![]; // otherwise compiler is interpreting as Vec<&&str>
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d0b4e82ab1eb12791a18cf6d33ad0ca4
I am really new to Rust, I am having trouble solving this error, but it only happens if I comment out the while statement , basicly I am asking values from the console and storing it in a HashMap:
use std::collections::HashMap;
use std::io;
fn main() {
let mut customers = HashMap::new();
let mut next_customer = true;
while next_customer {
let mut input_string = String::new();
let mut temp_vec = Vec::with_capacity(3);
let mut vec = Vec::with_capacity(2);
println!("Insert new customer f.e = customer id,name,address:");
io::stdin().read_line(&mut input_string);
input_string = input_string.trim().to_string();
for s in input_string.split(",") {
temp_vec.push(s);
}
vec.push(temp_vec[1]);
vec.push(temp_vec[2]);
let mut key_value = temp_vec[0].parse::<i32>().unwrap();
customers.insert(key_value, vec);
next_customer = false;
}
println!("DONE");
}
The code results in the error
error[E0597]: `input_string` does not live long enough
--> src/main.rs:14:18
|
14 | for s in input_string.split(",") {
| ^^^^^^^^^^^^ borrowed value does not live long enough
...
20 | customers.insert(key_value, vec);
| --------- borrow later used here
21 | next_customer = false;
22 | }
| - `input_string` dropped here while still borrowed
As others have said the problem lies with the lifetime and/or type of the values getting put into the customers map.
customers.insert(key_value, vec);
| --------- borrow later used here
Often this happens when the compiler has decided to give an object a type that you didn't expect. To find out what it's doing you can force the type, and see how it complains. Changing the code to:
let mut customers: HashMap<(),()> = HashMap::new();
Gives us two relevant errors:
20 | customers.insert(key_value, vec);
| ^^^^^^^^^ expected `()`, found `i32`
...
20 | customers.insert(key_value, vec);
| ^^^ expected `()`, found struct `std::vec::Vec`
|
= note: expected unit type `()`
found struct `std::vec::Vec<&str>`
So the type that the compiler wants to give our customers object is HashMap<i32, Vec<&str>>
The problem is that the &str lifetime has got to be inside the block as we don't store the Strings anywhere, and they can't have 'static lifetime since they're user input.
This means we probably want a HashMap<i32,Vec<String>>.
Changing the code to use one of those gives us an error about vec not having the right type: It's getting deduced as a Vec<&str>, but we want a Vec<String>.
We have two options.
Convert the vec to the right type just before we insert it into the map using customers.insert(key_value, vec.iter().map(|s| s.to_string()).collect()). (Though you may want to extract it to a variable for clarity).
Explicitly change the type of vec to Vec<String>
Option 1 "just works". While option 2 leads us down a path of making similar changes closer and closer to the read_line call.
Once you've decided on the fix in option 1, you can remove the manual type annotations that were added to work out the fix, if you find them overly noisy.
The issue is that you are passing around reference to underlying &str values that will get dropped. One way is to take the input string, trim and split it, then clone it going into the other vector.
let temp_vec: Vec<String> = input_string.trim().split(",").map(|t| t.to_string()).collect();
vec.push(temp_vec[1].clone());
vec.push(temp_vec[2].clone());