鉴于以下计划:
use std::collections::HashMap;
fn main() {
let mut hm = HashMap::new();
hm.insert(0, 1);
hm.insert(1, 1);
let mut iter = hm.iter();
println!("{:?}", iter.nth(0).expect("Fatal.").0)
}
我为代码的每次执行运行获得了不同的输出:
procyclinsur@procyclinsur:~/Documents/Rust/t1$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/t1`
1
procyclinsur@procyclinsur:~/Documents/Rust/t1$ vim src/main.rs
procyclinsur@procyclinsur:~/Documents/Rust/t1$ cargo run
Compiling t1 v0.1.0 (file:///home/procyclinsur/Documents/Rust/t1)
Finished dev [unoptimized + debuginfo] target(s) in 1.12 secs
Running `target/debug/t1`
1
procyclinsur@procyclinsur:~/Documents/Rust/t1$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/t1`
1
procyclinsur@procyclinsur:~/Documents/Rust/t1$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/t1`
0
procyclinsur@procyclinsur:~/Documents/Rust/t1$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/t1`
1
我希望每次运行程序都能看到相同的输出。有谁知道这个代码以这种方式表现的原因?如何让它按预期输出0?
答案 0 :(得分:7)
这是因为HashMap
是无序的。它的iter
method
以任意顺序
访问所有键值对
documentation on collections描述了这种行为:
对于像HashMap 这样的无序集合,将会产生这些项目 内部表示最方便的顺序。
为了始终检索特定值,您需要search by the key(或使用不依赖于订单的Iterator
methods之一,例如find
);例如:
use std::collections::HashMap;
fn main() {
let mut hm = HashMap::new();
hm.insert(0, "a");
hm.insert(1, "b");
println!("{:?}", hm.get(&0)) // always Some("a")
}
答案 1 :(得分:2)
值得一提的是BTreeMap
和相应的iter函数
获取地图条目的迭代器,按键排序。
这可能是一个简单的替代品。
use std::collections::BTreeMap;
fn main() {
let mut hm = BTreeMap::new();
hm.insert(0, 1);
hm.insert(1, 1);
let mut iter = hm.iter();
println!("{:?}", iter.nth(0).expect("Fatal.").0);
}
答案 2 :(得分:2)
正如其他人所说,订单是不可预测的。但是,使用不同的哈希可以至少为您提供可重现的结果。例如FNV hash function,您可以这样使用:
extern crate fnv;
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use fnv::FnvHasher;
type HashMapFnv<K, V> = HashMap<K, V, BuildHasherDefault<FnvHasher>>;
fn main() {
let mut hm = HashMapFnv::default();
hm.insert(0, 1);
hm.insert(1, 1);
let mut iter = hm.iter();
println!("{:?}", iter.nth(0).expect("Fatal.").0)
}
每次都应该给你相同的结果。但是,无法保证该订单是什么,因此如果您更新FNV或者使用不同版本的Rust本身,您可能会在不同的操作系统上获得不同的结果。
请注意,您不应在任何处理外部数据的应用程序中使用此哈希函数,因为它易受哈希冲突攻击。 Rust中的默认哈希函数是安全的。