|
|
|
@ -27,6 +27,8 @@ my_gems.insert("河边捡的误以为是宝石的破石头", 18);
|
|
|
|
|
|
|
|
|
|
所有的集合类型都是动态的,意味着它们没有固定的内存大小,因此它们底层的数据都存储在内存堆上,然后通过一个存储在栈中的引用类型来访问。同时,跟其它集合类型一致,`HashMap`也是内聚性的, 即所有的`K`必须拥有同样的类型,`V`也是如此。
|
|
|
|
|
|
|
|
|
|
> 跟Vec一样,如果预先知道要存储的KV对个数,可以使用`HashMap::with_capacity(capacity)`创建指定大小的HashMap,避免频繁的内存分配和拷贝,提升性能
|
|
|
|
|
|
|
|
|
|
#### 使用迭代器和collect方法创建
|
|
|
|
|
在实际使用中,不是所有的场景都能`new`一个哈希表后,然后悠哉悠哉的依次插入对应的键值对, 而是可能会从另外一个数据结构中,获取到对应的数据,最终生成`HashMap`.
|
|
|
|
|
|
|
|
|
@ -170,7 +172,7 @@ let score: Option<&i32> = scores.get(&team_name);
|
|
|
|
|
|
|
|
|
|
上面有几点需要注意:
|
|
|
|
|
- `get`方法返回一个`Option<&i32>`类型:当查询不到时,会返回一个`None`,查询到时返回`Some(&i32)`
|
|
|
|
|
- `&32`是对`HashMap`中值的借用,如果不使用借用,可能会发生所有权的转移
|
|
|
|
|
- `&i32`是对`HashMap`中值的借用,如果不使用借用,可能会发生所有权的转移
|
|
|
|
|
|
|
|
|
|
还可以通过循环的方式依次遍历`KV`对:
|
|
|
|
|
```rust
|
|
|
|
@ -254,7 +256,7 @@ println!("{:?}", map);
|
|
|
|
|
|
|
|
|
|
好了,理解完这个,再来设想一点,若一个复杂点的类型作为Key,那怎么在底层对它进行存储,怎么使用它进行查询和比较? 是不是很棘手?好在我们有哈希函数:通过它把`Key`计算后映射为哈希值,然后使用该哈希值来进行存储、查询、比较等操作。
|
|
|
|
|
|
|
|
|
|
但是问题又来了,如何保证不同`Key`通过哈希后的两个值不会相同?如果相同,那意味着我们使用不同的·,却查到了同一个结果,这种明显是错误的行为。
|
|
|
|
|
但是问题又来了,如何保证不同`Key`通过哈希后的两个值不会相同?如果相同,那意味着我们使用不同的Key,却查到了同一个结果,这种明显是错误的行为。
|
|
|
|
|
此时,就涉及到安全性跟性能的取舍了。
|
|
|
|
|
|
|
|
|
|
若要追求安全,尽可能减少冲突,同时防止拒绝服务(Denial of Service, DoS)攻击,就要使用密码学安全的哈希函数,`HashMap`就是使用了这样的哈希函数。反之若要追求性能,就需要使用没有那么安全的算法。
|
|
|
|
|