This question already has answers here:
How to lookup from and insert into a HashMap efficiently?
(2 answers)
Closed 6 years ago.
I have this code where pat_vec and str_vec are two iterators:
let mut pat_mapping: HashMap<char, &str> = HashMap::new();
for combi in pat_vec.zip(str_vec) {
let (c, word) = combi;
match pat_mapping.get(&c) {
Some(phrase) => {
if phrase.to_string() != word.to_string() {
return false;
}
}
None => {
pat_mapping.insert(c, word);
}
}
}
This does not work, and the compiler complains that:
cannot borrow `pat_mapping` as mutable because it is also borrowed as immutable [E0502]
I understand that it might because pat_mapping.get(&c) borrowed &self as immutable, while the insert() method falls into the same scope but needs to borrow &self as mutable.
I have a work around:
match word_mapping.get(&c) {
Some(phrase) => {
if phrase.to_string() != word.to_string() {
return false;
}
}
None => {
pat_trigger = true;
}
};
if pat_trigger {
pat_mapping.insert(c, word);
}
But introducing a boolean flag is redundant. Is there a way to work around the borrow check so as to do the match and insert in the same code block?
You want to use entry:
match pat_mapping.entry(c) {
Occupied(phrase) => {
if phrase.get().to_string() != word.to_string() {
return false;
}
},
Vacant(vacant) => {
vacant.insert(word);
}
}
It also has the advantage of looking up the key only once.
Related
I'm writing a function that returns a serde_json::Value upon success (and failure). Previously in Rust I have been omitting the semicolon to return data from a function, like in the code example below:
use serde_json::{Result, Value};
use core::result::Result as ResultCore;
fn returning_function() -> ResultCore<Value, Value> {
let data = r#"
{
"status": "ok",
"response": {
"data": "secret message!"
}
}
"#;
match str_to_json(data) {
Ok(json_data) => match json_data["status"].as_str() {
Some(status_str) => {
if status_str == "ok" {
Ok(json_data["response"].clone())
}
}
None => eprintln!("\"status\" was not a string")
}
Err(error) => eprintln!("something went wrong! here's what: {}", error)
}
Err(serde_json::Value::Null)
}
fn str_to_json(json_data: &str) -> Result<Value> {
Ok(serde_json::from_str(json_data)?)
}
Here comes the part I don't understand: this doesn't compile. Rust's compiler tells me "mismatched types", and that it expected type (), but found type serde_json::value::Value. Now, I found a solution to this that does compile, and it is as follows:
use serde_json::{Result, Value};
use core::result::Result as ResultCore;
fn returning_function() -> ResultCore<Value, Value> {
let data = r#"
{
"status": "ok",
"response": {
"data": "secret message!"
}
}
"#;
match str_to_json(data) {
Ok(json_data) => match json_data["status"].as_str() {
Some(status_str) => {
if status_str == "ok" {
return Ok(json_data["response"].clone());
// ^ added return statement here
}
}
None => eprintln!("\"status\" was not a string")
}
Err(error) => eprintln!("something went wrong! here's what: {}", error)
}
Err(serde_json::Value::Null)
}
fn str_to_json(json_data: &str) -> Result<Value> {
Ok(serde_json::from_str(json_data)?)
}
By adding the return statement the compiler suddenly is happy and the compiler doesn't have anything to say about it any more. Why is this? I was under the impression that omitting the semicolon and using the return statement had the same implications — why does it differ here?
A return statement, otherwise known as an early return, will return an object from the last/innermost function-like scope. (Function-like because it applies to both closures and functions)
let x = || {
return 0;
println!("This will never happen!");
};
fn foo() {
return 0;
println!("This won't happen either");
}
An absent semicolon will instead evaluate the expression, like a return, but only return to the last/innermost scope, or in other words, it returns from within any set of {}.
let x = { // Scope start
0
}; // Scope end
fn foo() -> usize { // Scope start
0
} // Scope end
return statement will break out of any amount of nested scopes until it hits a function-like scope:
fn foo() -> usize {// <------------------------------------------\
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
return 0; // ---/
}
}
}
}
}
}
}
}
}
}
}
}
The return statement also has a type of its own, that is to say that let x = return; will actually compile.
A return statement will evaluate to !, AKA the never type. You can't name it in stable rust right now, but it will eventually become stable and usable.
As it says in The Book:
In Rust, the return value of the function is synonymous with the value of the final expression in the block of the body of a function.
In other words - it is not the fact that an expression does not have a semicolon that makes it the return value, it is the fact that it is the final expression in the function. A semicolon is used to separate expressions, so this:
fn foo() -> i32 {
5;
}
is equivalent to an expression yielding the value 5, followed by an empty expression that does not yield anything. Thus the function above would not compile.
Where the return keyword comes in handy is if you want to return from a function early, before reaching the final expression. This is what you are trying to do in your example.
Also note that all potential return values have to have the same type as the return value of the function itself.
None of the above fully explains the compiler error you were getting though. Your inner match looks like this:
match json_data["status"].as_str() {
Some(status_str) => {
if status_str == "ok" {
Ok(json_data["response"].clone())
}
}
None => eprintln!("\"status\" was not a string")
}
One of the rules of match blocks is that each of the arms has to evaluate to the same type. But in the case above, one arm potentially evaluates to std::result::Result<serde_json::value::Value, _>, while the other does not evaluate to anything (or to be more precise, evaluates to the empty value ()).
Inserting the return avoids that error, because the Some arm now returns from the function altogether, rather than evaluating to a value of type std::result::Result<serde_json::value::Value, _>.
This question already has answers here:
Why is a borrow still held in the else block of an if let?
(5 answers)
How to update-or-insert on a Vec?
(2 answers)
Closed 4 years ago.
I'm storing some structs in a vector. In a loop I'm trying to process some input, and in every iteration I'd like to either insert a new item into the vector, or mutate an existing element (depending on whether it's already in the vector or not).
So I'm trying to do something like this.
struct Foo {
id: char,
data: i32,
}
fn main() {
let mut cache: Vec<Foo> = Vec::new();
for a in vec!['c'] {
let foo = cache.iter_mut().filter(|s| s.id == a).nth(0);
match foo {
Some(f) => {
f.data = f.data + 1;
}
None => {
cache.push(Foo { id: a, data: 0 });
}
}
}
}
I'm getting an error in the None arm saying
error[E0499]: cannot borrow `cache` as mutable more than once at a time
--> src/main.rs:17:17
|
10 | let foo = cache.iter_mut().filter(|s| s.id == a).nth(0);
| ----- first mutable borrow occurs here
...
17 | cache.push(Foo { id: a, data: 0 });
| ^^^^^ second mutable borrow occurs here
...
20 | }
| - first borrow ends here
What's the idiomatic way to avoid this issue? I tried the following workaround, which seems to work, but it feels very clunky.
for a in vec!['c'] {
let mut found = false;
{
let step = cache.iter_mut().filter(|s| s.id == a).nth(0);
match step {
Some(f) => {
f.data = f.data + 1;
found = true;
}
None => (),
}
}
if !found {
cache.push(Foo { id: a, data: 0 });
}
}
Is there an easier solution?
I'm writing a simple tokenizer in Rust but I'm having trouble. I've simplified the code a bit for the sake of this question:
use std::iter::Peekable;
use std::str::Chars;
struct Example<'a> {
it: Peekable<Chars<'a>>,
}
impl<'a> Example<'a> {
fn tokenize_string(&mut self) {
loop {
match self.it.peek() {
None => break,
Some(_x) => self.it.next(),
};
}
}
}
The error I'm getting is:
error[E0499]: cannot borrow `self.it` as mutable more than once at a time
--> src/main.rs:13:29
|
11 | match self.it.peek() {
| ------- first mutable borrow occurs here
12 | None => break,
13 | Some(_x) => self.it.next(),
| ^^^^^^^ second mutable borrow occurs here
14 | };
| - first borrow ends here
I've been able to work around this by creating a copy of the iterator and calling peek() on that:
fn tokenize_string(&mut self) {
loop {
let mut iterator = self.it.clone();
match iterator.peek() {
None => break,
Some(_x) => self.it.next(),
};
}
}
Is this the best way to do this? It seems a little hack-ish.
Since you're working with str::chars(), and char is Copy, you can dereference to get a char instead of &char. :
fn tokenize_string(&mut self) {
loop {
let r = self.it.peek().cloned();
let n = match r {
Some(_) => self.it.next(),
None => break,
};
// whatever
}
}
If you just want to check if the iterator has returned something, use is_some():
let r = self.it.peek().is_some();
if r { ... } else { ... }
In general, however, I'm not sure if it is possible exactly in this manner without non-lexical lifetimes. You will need to put the code which checks iterator state and the code which works with the iterator based on the state with scopes, something like this:
let r = {
// work with self.it
};
if r { ... } else { ... }
Here any references into self must not escape the lexical block in r, so there is no direct match on a value which contains references into self. There's further examples of working around this in Rust borrow of a HashMap lasts beyond the scope it's in?.
I'm writing a simple tokenizer in Rust but I'm having trouble. I've simplified the code a bit for the sake of this question:
use std::iter::Peekable;
use std::str::Chars;
struct Example<'a> {
it: Peekable<Chars<'a>>,
}
impl<'a> Example<'a> {
fn tokenize_string(&mut self) {
loop {
match self.it.peek() {
None => break,
Some(_x) => self.it.next(),
};
}
}
}
The error I'm getting is:
error[E0499]: cannot borrow `self.it` as mutable more than once at a time
--> src/main.rs:13:29
|
11 | match self.it.peek() {
| ------- first mutable borrow occurs here
12 | None => break,
13 | Some(_x) => self.it.next(),
| ^^^^^^^ second mutable borrow occurs here
14 | };
| - first borrow ends here
I've been able to work around this by creating a copy of the iterator and calling peek() on that:
fn tokenize_string(&mut self) {
loop {
let mut iterator = self.it.clone();
match iterator.peek() {
None => break,
Some(_x) => self.it.next(),
};
}
}
Is this the best way to do this? It seems a little hack-ish.
Since you're working with str::chars(), and char is Copy, you can dereference to get a char instead of &char. :
fn tokenize_string(&mut self) {
loop {
let r = self.it.peek().cloned();
let n = match r {
Some(_) => self.it.next(),
None => break,
};
// whatever
}
}
If you just want to check if the iterator has returned something, use is_some():
let r = self.it.peek().is_some();
if r { ... } else { ... }
In general, however, I'm not sure if it is possible exactly in this manner without non-lexical lifetimes. You will need to put the code which checks iterator state and the code which works with the iterator based on the state with scopes, something like this:
let r = {
// work with self.it
};
if r { ... } else { ... }
Here any references into self must not escape the lexical block in r, so there is no direct match on a value which contains references into self. There's further examples of working around this in Rust borrow of a HashMap lasts beyond the scope it's in?.
The code is something like the following, in a function that is an implementation for a Context struct, defined as the following:
struct Context {
lines: isize,
buffer: Vec<String>,
history: Vec<Box<Instruction>>,
}
And the function, of course as an implementation:
fn _execute_history(&mut self, instruction: &Instruction) -> Reaction {
let num = instruction.suffix.parse::<usize>();
match num {
Ok(number) => {
match self.history.get(number) {
Some(ins) => { return self.execute(*ins); },
_ => { /* Error handling */ }
}
}
Err(..) => { /* Error handling */ }
}
}
This doesn't compile and I don't understand the error message. I searched online for similar problems and I cannot seem to grasp the problem here. I am from a Python background. The full error:
hello.rs:72:23: 72:35 note: previous borrow of `self.history[..]` occurs here; the immutable
borrow prevents subsequent moves or mutable borrows of `self.history[..]` until the borrow ends
I am fully aware that the function is not conforming to the type system, but this is because the simplified code is for demonstrative purposes only.
You borrow a value from self.history with get and that borrow is still "alive" when you call execute on self (that requires &mut self from what I can see from the error)
In this case return your value from the match and call self.execute after the match:
fn _execute_history(&mut self, instruction: &Instruction) -> Reaction {
let num = instruction.suffix.parse::<usize>();
let ins = match num {
Ok(number) => {
match self.history.get(number) {
Some(ins) => ins.clone(),
_ => { /* Error handling */ panic!() }
}
}
Err(..) => { /* Error handling */ panic!() }
};
self.execute(ins)
}