For循环不按顺序打印哈希映射

For loop not printing hash map in order

我不明白为什么没有按顺序打印散列图。分配密钥时是否以这种方式保存?用肉眼看,它似乎是随机的。这对 Rust 来说是正常的吗?

use std::collections::HashMap;
use rand::Rng;

fn main() {
    let mut board = HashMap::new();
    
    for n in 0..99 {
        board.insert(n,0);
    }
    // board.insert(1, 0);

    for (key,value) in &board {
        println!("{}: {}", key, value);
    }
}

输出:

21: 0
15: 0
90: 0
10: 0
52: 0
92: 0
32: 0
61: 0
91: 0
50: 0
28: 0
93: 0
64: 0
72: 0
75: 0
95: 0
98: 0
89: 0
57: 0
88: 0
9: 0
85: 0
87: 0
24: 0
29: 0
37: 0
19: 0
16: 0
44: 0
51: 0
79: 0
53: 0
73: 0
11: 0
7: 0
59: 0
62: 0
3: 0
74: 0
14: 0
96: 0
34: 0
40: 0
23: 0
86: 0
49: 0
82: 0
54: 0
80: 0
22: 0
31: 0
60: 0
76: 0
12: 0
0: 0
2: 0
97: 0
83: 0
27: 0
33: 0
69: 0
26: 0
46: 0
68: 0
43: 0
71: 0
58: 0
77: 0
17: 0
5: 0
35: 0
65: 0
56: 0
20: 0
48: 0
1: 0
13: 0
30: 0
4: 0
41: 0
55: 0
45: 0
25: 0
47: 0
63: 0
66: 0
6: 0
67: 0
38: 0
70: 0
81: 0
84: 0
39: 0
18: 0
42: 0
8: 0
78: 0
36: 0
94: 0

哈希图的目的不是保持插入键的顺序。它用于快速数据查找。 可能会帮助您找到解决方案

通常,哈希映射的工作原理是将键映射到存储桶中,方法是对这些键应用哈希函数,然后将值存储在该存储桶中。对于可以接受不可信数据的通用哈希映射,有必要使用加密安全的随机哈希函数(技术上称为PRF),这样攻击者就不会通过将许多密钥哈希到一个桶中来导致病态性能。

Rust 实现了一个使用这种方法的 hashmap,许多其他语言也是如此(尽管值得注意的是,上次我检查过,PHP 没有)。由于这种方法,hashmap 在内部是无序的,它的项目将以任意顺序存储,这通常因实例而异。

一些语言,如Ruby,明确选择实现对象的插入顺序遍历,这在很多情况下非常方便。然而,这不是免费的,因为 Rust 旨在尽可能避免昂贵的开销。因此,您有一些选择:

  • 如果您需要按键对对象进行排序,或者只是以某种确定的顺序(例如,用于测试),您可以使用 BTreeMap,它提供按键排序的顺序。请注意,这与 HashMap 具有不同的性能特征,并且需要不同的键(具体来说,它们是 Ord 而不是 Hash)。
  • 如果您特别需要广告订单,您可能会找到提供此功能的箱子,例如 indexmaplinked_hash_map

由于 Hashmap 是一个可增长的结构,它由调用者动态分配,但它可能会在 运行 行期间停止,由于 OS 在与您相同的核心上执行的其他任务正在使用。

由于某些 OS 级别限制,hashmap 在其他结构之上存在局限性和优势。

运行时内存排序

  • 然后哈希图增长,但内存排序不是严格线性的,因为它不是以固定数量的引用开始的。


  • 对象分配

  • 最后,完整的块由打印调用函数以其分配的方式表示,与分配后由 OS 静态链接线程重新排序后写入的数据无关。


  • 该结构使 hashmap 非常快,因为不需要根据初始计数对 refs 进行原子计数和排序;它们的排序方式是基于键本身,而不是基于预分配的引用计数。


  • hashmap 的此类键由调用函数以非精确线性方式存储,并引用链接到它们所持有的对象。因此代表了所描述的方式。


  • 基于 VM 的语言

  • 最后一件需要注意的重要事情是,某些语言(如 Rust 本身)在 运行 编写您编写的一些代码时捕捉到 OS 信号,这是某种形式的基本 VM(虚拟机) 自行捕获(嵌入在您的 exe 中的 rust 库)应用程序中可能的分配或 运行 时间错误。

  • 以前的语言不进行 运行 时间检查,而二进制文件本身是 运行。其他语言确实有自己的堆栈,例如 Java 本身就是一个完整的虚拟机的实例。虚拟机可以及时缓解很多与引用分配相关的问题,进而为语言模型中更坚实的对象引用提供基础。