Use Index trait with HashMap in Rust [duplicate] - hashmap

This question already has answers here:
How can I update a value in a mutable HashMap?
(4 answers)
Closed 5 years ago.
In order to test the Index trait, I coded a histogram.
use std::collections::HashMap;
fn main() {
let mut histogram: HashMap<char, u32> = HashMap::new();
let chars: Vec<_> = "Lorem ipsum dolor sit amet"
.to_lowercase()
.chars()
.collect();
for c in chars {
histogram[c] += 1;
}
println!("{:?}", histogram);
}
Test code here.
But I get following type error expected &char, found char. If I use histogram[&c] += 1; instead, I get cannot borrow as mutable.
What am I doing wrong? How can I fix this example?

HashMap only implements Index (and not IndexMut):
fn index(&self, index: &Q) -> &V
so you can't mutate histogram[&c], because the returned reference &V is immutable.
You should use the entry API instead:
for c in chars {
let counter = histogram.entry(c).or_insert(0);
*counter += 1;
}

Related

Mutably borrow a hash map inside a loop [duplicate]

This question already has answers here:
Why does this mutable borrow live beyond its scope?
(2 answers)
Closed 8 months ago.
I'd like to mutably borrow a hash map on every iteration of a loop.
I have the following hash map, function, and loop:
use std::collections::HashMap;
fn func<'a>(hash_map: &'a mut HashMap<&'a str, String>) {
unimplimented!();
}
fn loop() {
let mut hash_map = HashMap::new();
let mut i = 0;
while i < 10 {
func(&mut hash_map);
i += 1;
}
}
This will produce the following error on the func(&mut hash_map); line:
cannot borrow `hash_map` as mutable more than once at a time
`hash_map` was mutably borrowed here in the previous iteration of the looprustc(E0499)
main.rs(62, 25): `hash_map` was mutably borrowed here in the previous iteration of the loop
How can I refactor this to be able to mutably borrow the hash map on every iteration of the loop?
I believe I understand Rust's ownership rules enough to understand why this error is happening, just not well enough to fix it.
Note: I know there are better ways to write a loop in Rust, just wanted a very simple loop for this example.
Looks like I was using an unneeded lifetime in the function argument type definition. Instead of hash_map: &'a mut HashMap<&'a str, String>, I could just use hash_map: &mut HashMap<&'a str, String>.
The following code works for me.
use std::collections::HashMap;
use external::func;
fn func<'a>(hash_map: &mut HashMap<&'a str, String>) {
unimplimented!();
}
fn loop() {
let mut hash_map = HashMap::new();
let mut i = 0;
while i < 10 {
func(&mut hash_map);
i += 1;
}
}

Does a mutable String reference implement Copy [duplicate]

This question already has answers here:
Why is the mutable reference not moved here?
(4 answers)
Do mutable references have move semantics?
(1 answer)
Closed 1 year ago.
In the below code I was expecting the compiler to complain about use of moved value: xref on hello function's second call since mutable references do not implement Copy. The compiler doesn't raise any such error. What am I missing here?
fn main() {
let mut x: String = "Developer".to_string();
let x_ref: &mut String = &mut x;
hello(x_ref);
hello(x_ref);
}
fn hello(a: &mut String) {
println!("Hello {}", a);
}
Your example uses the mutable references after each other, which allows the compiler to perform an implicit reborrow. It basically turns this code into this:
hello(&mut *x_ref);
hello(&mut *x_ref);
Now you have two separate mutable borrows each only for the lifetime of the function call, thus they do not conflict with each other.
You see an error if you try to use it two times simultaneously.
fn main() {
let mut x: String = "Developer".to_string();
let x_ref: &mut String = &mut x;
hello(x_ref, x_ref);
}
fn hello(a: &mut String, b: &mut String) {
println!("Hello {} and {}", a, b);
}

What's the difference between &String and &str in a function signature? [duplicate]

This question already has answers here:
What are the differences between Rust's `String` and `str`?
(14 answers)
Why is it discouraged to accept a reference &String, &Vec, or &Box as a function argument?
(4 answers)
Closed 1 year ago.
Considering the following program:
fn main() {
let s = String::from("helloworld");
// This works fine
println!("The first word is: {}", first_word(&s));
// This won't compile
println!("The first word is: {}", first_word(&s[..]));
// This works fine
println!("The first word is: {}", first_word1(&s));
// This works fine
println!("The first word is: {}", first_word1(&s[..]));
}
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
s
}
fn first_word1(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
It seems that for a &str parameter, you can use either a &String or a &str as argument, but for a &String parameter, only &String is allowed.
It also seems that if a function returns &str in its signature, it can return either a &String or a &str, the caller of the function won't see any difference.
So my question is, what is the difference between &String and &str, in parameter types and return types of rust function signatures?

rust: expected lifetime parameter problem [duplicate]

This question already has answers here:
How to return new data from a function as a reference without borrow checker issues?
(1 answer)
Return local String as a slice (&str)
(7 answers)
Closed 3 years ago.
I am new to Rust and was making a simple program to practice which takes 2 numbers and prints the numbers between them. This is my code
fn main() {
let a: u32 = 2;
let b: u32 = 10;
let a = result(&a, &b);
println!("{:?}", a);
}
fn result(a: &u32, b: &u32) -> [Vec<&u32>] {
let mut vec = Vec::new();
for x in a..b {
vec.push(a);
}
vec
}
When i run this program, i get this error
fn result(a: &u32, b: &u32) -> [Vec<&u32>] {
| ^ expected lifetime parameter
The concepts of borrowing and lifetimes are still very new and strange to me. Please help me in determining where i am wrong.
The error message is quite clear here:
this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from a or b
Providing an explicit lifetime would help the compiler understand what you're trying to do:
fn result<'a>(a: &'a u32, b: &'a u32) -> Vec<&'a u32> {
let mut vec: Vec<&'a u32> = Vec::new();
for x in *a..*b {
vec.push(&x);
}
vec
}
But the above wouldn't work either, as borrowing x results in borrowing a variable whch only lives in the scope a single iteration:
vec.push(&x);
^^ borrowed value does not live long enough
What you probably want is to avoid borrowing altogether:
fn result(a: u32, b: u32) -> Vec<u32> {
let mut vec = Vec::new();
for x in a..b {
vec.push(x);
}
vec
}
live example on godbolt.org

How to pass a HashMap to a function in Rust [duplicate]

This question already has answers here:
What's the difference between placing "mut" before a variable name and after the ":"?
(4 answers)
Closed 6 years ago.
Can anybody explain why following code does not compile?
use std::collections::HashMap;
fn add(mut h: &HashMap<&str, &str>) {
h.insert("foo", "bar");
}
fn main() {
let mut h: HashMap<&str, &str> = HashMap::new();
add(&h);
println!("{:?}", h.get("foo"));
}
This is what rustc tells me
hashtest.rs:4:5: 4:6 error: cannot borrow immutable borrowed content `*h` as mutable
hashtest.rs:4 h.insert("foo", "bar");
^
The problem is that you pass a mutable reference to a HashMap (i.e. the reference can be changed to point to another HashMap), and not a reference to a mutable HashMap (i.e. the HashMap can change).
Here is a correct code:
use std::collections::HashMap;
fn add(h: &mut HashMap<&str, &str>) {
h.insert("foo", "bar");
}
fn main() {
let mut h: HashMap<&str, &str> = HashMap::new();
add(&mut h);
println!("{:?}", h.get("foo"));
}

Resources