update HashMap.md
This commit is contained in:
parent
c38f124a31
commit
009f6ac52e
|
@ -71,3 +71,92 @@ fn main() {
|
||||||
println!("Success!")
|
println!("Success!")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
3.
|
||||||
|
```rust
|
||||||
|
// FILL in the blanks
|
||||||
|
use std::collections::HashMap;
|
||||||
|
fn main() {
|
||||||
|
// type inference lets us omit an explicit type signature (which
|
||||||
|
// would be `HashMap<&str, u8>` in this example).
|
||||||
|
let mut player_stats = HashMap::new();
|
||||||
|
|
||||||
|
// insert a key only if it doesn't already exist
|
||||||
|
player_stats.entry("health").or_insert(100);
|
||||||
|
|
||||||
|
assert_eq!(player_stats["health"], 100);
|
||||||
|
|
||||||
|
// insert a key using a function that provides a new value only if it
|
||||||
|
// doesn't already exist
|
||||||
|
player_stats.entry("health").or_insert_with(random_stat_buff);
|
||||||
|
assert_eq!(player_stats["health"], 100);
|
||||||
|
|
||||||
|
// Ensures a value is in the entry by inserting the default if empty, and returns
|
||||||
|
// a mutable reference to the value in the entry.
|
||||||
|
let health = player_stats.entry("health").or_insert(50);
|
||||||
|
assert_eq!(health, &100);
|
||||||
|
*health -= 50;
|
||||||
|
assert_eq!(*health, 50);
|
||||||
|
|
||||||
|
println!("Success!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_stat_buff() -> u8 {
|
||||||
|
// could actually return some random value here - let's just return
|
||||||
|
// some fixed value for now
|
||||||
|
42
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4.
|
||||||
|
```rust
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Hash, Eq, PartialEq, Debug)]
|
||||||
|
struct Viking {
|
||||||
|
name: String,
|
||||||
|
country: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Viking {
|
||||||
|
/// Creates a new Viking.
|
||||||
|
fn new(name: &str, country: &str) -> Viking {
|
||||||
|
Viking {
|
||||||
|
name: name.to_string(),
|
||||||
|
country: country.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Use a HashMap to store the vikings' health points.
|
||||||
|
let vikings = HashMap::from([
|
||||||
|
(Viking::new("Einar", "Norway"), 25),
|
||||||
|
(Viking::new("Olaf", "Denmark"), 24),
|
||||||
|
(Viking::new("Harald", "Iceland"), 12),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Use derived implementation to print the status of the vikings.
|
||||||
|
for (viking, health) in &vikings {
|
||||||
|
println!("{:?} has {} hp", viking, health);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
5.
|
||||||
|
```rust
|
||||||
|
use std::collections::HashMap;
|
||||||
|
fn main() {
|
||||||
|
let v1 = 10;
|
||||||
|
let mut m1 = HashMap::new();
|
||||||
|
m1.insert(v1, v1);
|
||||||
|
println!("v1 is still usable after inserting to hashmap : {}", v1);
|
||||||
|
|
||||||
|
// &str implements Copy trait
|
||||||
|
let v2 = "hello";
|
||||||
|
let mut m2 = HashMap::new();
|
||||||
|
m2.insert(v2, v1);
|
||||||
|
|
||||||
|
assert_eq!(v2, "hello");
|
||||||
|
}
|
||||||
|
```
|
|
@ -102,8 +102,119 @@ fn random_stat_buff() -> u8 {
|
||||||
```
|
```
|
||||||
|
|
||||||
### Requirements of HashMap key
|
### Requirements of HashMap key
|
||||||
`HashMap` keys can be booleans, integers, strings, or any other type that implements the Eq and Hash traits.
|
Any type that implements the `Eq` and `Hash` traits can be a key in `HashMap`. This includes:
|
||||||
|
|
||||||
|
- `bool` (though not very useful since there is only two possible keys)
|
||||||
|
- `int`, `uint`, and all variations thereof
|
||||||
|
- `String` and `&str` (tips: you can have a `HashMap` keyed by `String` and call `.get()` with an `&str`)
|
||||||
|
|
||||||
|
Note that `f32` and `f64` do not implement `Hash`, likely because [floating-point precision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems) errors would make using them as hashmap keys horribly error-prone.
|
||||||
|
|
||||||
|
All collection classes implement `Eq` and `Hash` if their contained type also respectively implements `Eq` and `Hash`. For example, `Vec<T>` will implement `Hash` if `T`implements `Hash`.
|
||||||
|
|
||||||
|
4. 🌟🌟
|
||||||
|
```rust,editable
|
||||||
|
|
||||||
|
// FIX the errors
|
||||||
|
// Tips: `derive` is usually a good way to implement some common used traits
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
struct Viking {
|
||||||
|
name: String,
|
||||||
|
country: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Viking {
|
||||||
|
/// Creates a new Viking.
|
||||||
|
fn new(name: &str, country: &str) -> Viking {
|
||||||
|
Viking {
|
||||||
|
name: name.to_string(),
|
||||||
|
country: country.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Use a HashMap to store the vikings' health points.
|
||||||
|
let vikings = HashMap::from([
|
||||||
|
(Viking::new("Einar", "Norway"), 25),
|
||||||
|
(Viking::new("Olaf", "Denmark"), 24),
|
||||||
|
(Viking::new("Harald", "Iceland"), 12),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Use derived implementation to print the status of the vikings.
|
||||||
|
for (viking, health) in &vikings {
|
||||||
|
println!("{:?} has {} hp", viking, health);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Capacity
|
### Capacity
|
||||||
Like vectors, HashMaps are growable, but HashMaps can also shrink themselves when they have excess space. You can create a HashMap with a certain starting capacity using HashMap::with_capacity(uint), or use HashMap::new() to get a HashMap with a default initial capacity (recommended).
|
Like vectors, HashMaps are growable, but HashMaps can also shrink themselves when they have excess space. You can create a `HashMap` with a certain starting capacity using `HashMap::with_capacity(uint)`, or use `HashMap::new()` to get a HashMap with a default initial capacity (recommended).
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
```rust,editable
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
fn main() {
|
||||||
|
let mut map: HashMap<i32, i32> = HashMap::with_capacity(100);
|
||||||
|
map.insert(1, 2);
|
||||||
|
map.insert(3, 4);
|
||||||
|
// indeed ,the capacity of HashMap is not 100, so we can't compare the equality here.
|
||||||
|
assert!(map.capacity() >= 100);
|
||||||
|
|
||||||
|
// Shrinks the capacity of the map with a lower limit. It will drop
|
||||||
|
// down no lower than the supplied limit while maintaining the internal rules
|
||||||
|
// and possibly leaving some space in accordance with the resize policy.
|
||||||
|
|
||||||
|
map.shrink_to(50);
|
||||||
|
assert!(map.capacity() >= 50);
|
||||||
|
|
||||||
|
// Shrinks the capacity of the map as much as possible. It will drop
|
||||||
|
// down as much as possible while maintaining the internal rules
|
||||||
|
// and possibly leaving some space in accordance with the resize policy.
|
||||||
|
map.shrink_to_fit();
|
||||||
|
assert!(map.capacity() >= 2);
|
||||||
|
println!("Success!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ownership
|
||||||
|
For types that implement the `Copy` trait, like `i32` , the values are copied into `HashMap`. For owned values like `String`, the values will be moved and `HashMap` will be the owner of those values.
|
||||||
|
|
||||||
|
5. 🌟🌟
|
||||||
|
```rust,editable
|
||||||
|
// FIX the errors with least changes
|
||||||
|
// DON'T remove any code line
|
||||||
|
use std::collections::HashMap;
|
||||||
|
fn main() {
|
||||||
|
let v1 = 10;
|
||||||
|
let mut m1 = HashMap::new();
|
||||||
|
m1.insert(v1, v1);
|
||||||
|
println!("v1 is still usable after inserting to hashmap : {}", v1);
|
||||||
|
|
||||||
|
let v2 = "hello".to_string();
|
||||||
|
let mut m2 = HashMap::new();
|
||||||
|
// ownership moved here
|
||||||
|
m2.insert(v2, v1);
|
||||||
|
|
||||||
|
assert_eq!(v2, "hello");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Third-party Hash libs
|
||||||
|
If the performance of `SipHash 1-3` doesn't meet your requirements, you can find replacements in crates.io or github.com.
|
||||||
|
|
||||||
|
The usage of third-party hash looks like this:
|
||||||
|
```rust
|
||||||
|
use std::hash::BuildHasherDefault;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
// introduce a third party hash function
|
||||||
|
use twox_hash::XxHash64;
|
||||||
|
|
||||||
|
|
||||||
|
let mut hash: HashMap<_, _, BuildHasherDefault<XxHash64>> = Default::default();
|
||||||
|
hash.insert(42, "the answer");
|
||||||
|
assert_eq!(hash.get(&42), Some(&"the answer"));
|
||||||
|
```
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue