This question already has answers here:
How to lookup from and insert into a HashMap efficiently?
(2 answers)
Is there any way to return a reference to a variable created in a function?
(5 answers)
Closed 4 years ago.
I'm trying to build a HashMap with vectors as values and I have problems with borrowing / lifetimes.
The task is to find the funniest words in a given text as ranked by the funny_score method. I would like to store a list of words for each distinct score in a HashMap.
I have the following code
use std::collections::HashMap;
fn main() {
let text = "";
let mut scores: HashMap<usize, &mut Vec<&str>> = HashMap::new();
for word in text.split(' ') {
let funny_score = funny_score(word);
match scores.get_mut(&funny_score) {
Some(list) => list.push(word),
None => {
let mut list = vec![word];
scores.insert(funny_score, &mut list);
}
}
}
}
fn funny_score(_: &str) -> usize { 0 }
And the compiler says
error[E0597]: `list` does not live long enough
--> src/main.rs:12:49
|
12 | scores.insert(funny_score, &mut list);
| ^^^^ borrowed value does not live long enough
13 | }
| - `list` dropped here while still borrowed
...
16 | }
| - borrowed value needs to live until here
error[E0499]: cannot borrow `scores` as mutable more than once at a time
--> src/main.rs:12:17
|
8 | match scores.get_mut(&funny_score) {
| ------ first mutable borrow occurs here
...
12 | scores.insert(funny_score, &mut list);
| ^^^^^^ second mutable borrow occurs here
13 | }
14 | }
| - first borrow ends here
How can I make this work?
Related
I have this code, but its giving me an error I don't understand:
fn main() {
// --snip--
let mut unit = String::new();
std::io::stdin()
.read_line(&mut unit)
.expect("couldn't read line!");
let unit = unit.trim().to_lowercase();
dbg!(unit);
if unit == "f" {
println!("temperature in Celsius is : {}°c", f_to_c(temp));
} else if unit == "c" {
println!("temperature in Fahrenheit is : {}°f", c_to_f(temp));
} else {
println!("'{unit}' unit not supported!");
}
}
error[E0382]: borrow of moved value: `unit`
--> src/lib.rs:16:8
|
13 | let unit = unit.trim().to_lowercase();
| ---- move occurs because `unit` has type `String`, which does not implement the `Copy` trait
14 | dbg!(unit);
| ---------- value moved here
15 |
16 | if unit == "f" {
| ^^^^ value borrowed here after move
I made unit explicitly type String but that wasn't the cause. How is this error is generated?
The dbg! macro moves it's arguments.
You can use it and not consume the argument by passing only a reference like this:
dbg!(&unit);
instead.
I have the following python function that removes consecutive duplicated numbers in-place (meaning [0, 0, 1, 1, 1, 2, 2, 3] becomes [0, 1, 2, 3]):
def del_consec_dupl(nums: List[int]):
for (idx, n) in enumerate(nums):
while idx < len(nums) - 1 and n == nums[idx + 1]:
del nums[idx]
it needs to be rewritten in Rust while respecting the constraint that it must work in-place without allocating an extra vector/array. When trying to literally translating this:
fn del_consec_dupl(nums: &mut Vec<i32>) {
for (idx, n) in nums.iter().enumerate() {
while idx < nums.len() - 1 && *n == nums[idx + 1] {
nums.remove(idx);
}
}
}
will produce the following errors:
error[E0502]: cannot borrow `*nums` as immutable because it is also borrowed as mutable
--> src/main.rs:4:21
|
3 | for (idx, n) in nums.iter_mut().enumerate() {
| ---------------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
4 | while idx < nums.len() - 1 && *n == nums[idx + 1] {
| ^^^^ immutable borrow occurs here
error[E0502]: cannot borrow `*nums` as immutable because it is also borrowed as mutable
--> src/main.rs:4:45
|
3 | for (idx, n) in nums.iter_mut().enumerate() {
| ---------------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
4 | while idx < nums.len() - 1 && *n == nums[idx + 1] {
| ^^^^ immutable borrow occurs here
error[E0499]: cannot borrow `*nums` as mutable more than once at a time
--> src/main.rs:5:13
|
3 | for (idx, n) in nums.iter_mut().enumerate() {
| ---------------------------
| |
| first mutable borrow occurs here
| first borrow later used here
4 | while idx < nums.len() - 1 && *n == nums[idx + 1] {
5 | nums.remove(idx);
| ^^^^ second mutable borrow occurs here
error: aborting due to 3 previous errors
it seems no matter what I do, I can only solve 2 of 3. It seems the main issue here is trying to refer to the length of the vector while it is being mutated inside the iteration.
Would I need an unsafe block here? or how would you go about solving it?
I would not use remove which moves all the elements after the given index and is inefficient, but just overwrite elements in the same array, dealing with the double-borrow problem by using indexes:
fn del_consec_dupl(nums: &mut Vec<i32>) {
let mut di = 0; // "destination" increment
for si in 1..nums.len() { // increment on the "source"
if nums[si] != nums[si-1] {
di += 1;
nums[di] = nums[si];
}
}
nums.truncate(di+1); // cut off the tail
}
There's no need to use unsafe here.
Rust vectors provide the built-in dedup() method which does exactly what you are asking for, so the easiest way to write your code is nums.dedup();.
For integers, or more generally Copy types, you can also implement the same functionality using the retain() method:
fn retain_uniq<T: Copy + PartialEq>(nums: &mut Vec<T>) {
let mut previous = None;
nums.retain(|&x| Some(x) != std::mem::replace(&mut previous, Some(x)))
}
I'm not sure if there is a better way to do this but was wondering how can I make sure that all the types of a record are accurate. I tried the following code below (making a recursive function to search the record) and was going to put matches for every level / scenario... I'm somewhat new to OCaml (more of a C and Python guy) so I'm struggling with this syntax.
type typeA= Int | Bool | List of typeA
type highestLevelObject= typeA* typeB and typeB=
|Float of float
| BoolLit of bool
| Int of int
| Seq of highestLevelObjectlist
| Bool of bool
(* The function to ensure my Object came in good *)
let rec verifyFields (highestLevelObject: highestLevelObject): bool =
match highestLevelObject with
| int-> true
| bool -> true
| _ -> verifyFields highestLevelObject
This compiles with warnings...
Warning 10: this expression should have type unit. (regarding _ -> case)
Warning 11: this match case is unused. (regarding _ -> case and bool -> case)
oddly
There must be something special with the List and getting a base case here... is matching each type manually or if there is a better(more elegant) way to do this?
Looking at https://ocaml.org/learn/tutorials/data_types_and_matching.html also but still struggling.
In the pattern matching, you should deconstruct data using data constructors, like this
match highestLevelObject with
| Int -> true
| Bool -> true
| Seq objs -> ...
| _ -> false
Notice the capitalized Int which is the data constructor, contrary to int which is just a variable name, so when you write
match highestLevelObject with
| int -> ...
it is the same as saying
match highestLevelObject with
| anything -> ...
in fact, anything here could be any variable name, which will match any data and bind itself to it. In other words, match x with y -> f y is the same as let y = x in f y
I would like to create a vector of HashMaps in Rust. I have tried the following:
fn main() -> Vec<HashMap<String, String>> {
let mut foo = HashMap::new();
foo.insert("".to_string(), "".to_string());
let f = Vec::new();
f.push(foo);
f
}
But I always get:
error[E0580]: main function has wrong type
--> src/main.rs:9:1
|
9 | / fn main() -> Vec<HashMap<String, String>> {
10 | | let mut foo = HashMap::new();
11 | | foo.insert("".to_string(), "".to_string());
12 | | let f = Vec::new();
13 | | f.push(foo);
14 | | f
15 | | }
| |_^ expected (), found struct `std::vec::Vec`
|
= note: expected type `fn()`
found type `fn() -> std::vec::Vec<std::collections::HashMap<std::string::String, std::string::String>>`
You try to return a value from fn main(), which isn't possible.
It will work if you rename your function and call it from main:
fn create_map() -> Vec<HashMap<String, String>> {
let mut foo = HashMap::new();
foo.insert("".to_string(), "".to_string());
let mut f = Vec::new();
f.push(foo);
f
}
fn main() {
create_map();
}
Playground
However, you also forgot to add mut to let f = Vec::new();
The compiler error has nothing to do with your vector or hashmap. It just states: "main function has wrong type". In Rust, every executable program starts at the function called main (located at the crate root). So that function name has a special meaning and a function called main at the crate root has to have a special signature (namely no arguments and () return type).
So you can fix the error by renaming your function and adding a mut. But you can write your code a bit more idiomatic with the vec![] macro:
fn get_vector() -> Vec<HashMap<String, String>> {
let mut foo = HashMap::new();
foo.insert("".to_string(), "".to_string());
vec![foo]
}
(Playground)
The following program tries to grade the marks of a student:
use std::io;
fn main() {
let mut in0 = String::new();
io::stdin().read_line(&mut in0).expect("stdin err");
let n: i32 = in0.trim().parse().expect("parse err");
println!("{}", n);
let mut v: Vec<i32> = Vec::new();
for _ in 0..n {
let mut inp = String::new();
io::stdin().read_line(&mut inp).expect("stdin err");
let num: i32 = inp.trim().parse().unwrap();
v.push(num);
}
let out: Vec<_> = v
.iter()
.map(|x| {
if x < 38 {
x
} else if x % 5 > 3 {
x + x % 5
} else {
x
}
})
.collect();
println!("{:?}", v);
}
While compiling, I get the following error.
error[E0308]: mismatched types
--> src/main.rs:19:20
|
19 | if x < 38 {
| ^^
| |
| expected `&i32`, found integer
| help: consider borrowing here: `&38`
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:24:17
|
21 | } else if x % 5 > 3 {
| ____________________-
22 | | x + x % 5
| | --------- expected because of this
23 | | } else {
24 | | x
| | ^ expected `i32`, found `&i32`
25 | | }
| |_____________- `if` and `else` have incompatible types
|
help: consider dereferencing the borrow
|
23 | } else *{
24 | x
25 | }
How is the x variable a &i32 type and not a i32 type?
Calling the .iter() method on a vector returns an iterator over references the vector's elements. Otherwise, it would have to move or copy the elements out of the vector, which is not desirable in the general case [1]. In the documentation this is not immediately obvious from the declaration:
pub fn iter(&self) -> Iter<T> // Return type does not look like a reference
However, the examples show that you get a reference:
assert_eq!(iterator.next(), Some(&1)); // note the `&1` instead of just `1`
The closure can be instructed to dereference the parameter:
v.iter().map(|&x| { /* do something */ })
This is fine if the vector contains Copyable types like i32. Otherwise this would result in a cannot move out of borrowed content error. In this case you will likely want to work with a reference anyway.
If you no longer need the vector after iterating you can use .into_iter(), which consumes the vector and iterates over owned items instead of references.
[1] Moving would clear the vector, which is covered by the .drain() method, and copying is not possible/efficient on all types.
If you want to consume the Vec, you must use into_iter() method:
use std::io;
fn main() {
let mut in0 = String::new();
io::stdin().read_line(&mut in0).expect("stdin err");
let n: i32 = in0.trim().parse().expect("parse err");
println!("{}", n);
let mut v: Vec<i32> = Vec::new();
for _ in 0 .. n {
let mut inp = String::new();
io::stdin().read_line(&mut inp).expect("stdin err");
let num: i32 = inp.trim().parse().unwrap();
v.push(num);
}
let out: Vec<_> = v.into_iter().map(|x| {
if x < 38 {
x
} else if x % 5 > 3 {
x + x % 5
} else {
x
}
}).collect();
println!("{:?}", out);
}
If you do not consume the vector, the things inside it can only be borrowed, not moved.