大佬 我想问下 ,match 和 hash map 哪个好呢?match 会有性能问题吗

来源:1-2 课程导学

emoPokey

2023-09-14

大佬 我想问下 ,match 和 hash map 哪个好呢?match 会有性能问题吗
对这个match 理解不深,感觉没有 switch 好用啊,但是 switch是有性能问题的

写回答

1回答

叶枭

2023-09-22

Rust 官方的态度是对于非稀疏的 match…case, 编译器可以将相关代码优化为查表, 也就是 O(1) 复杂度. 但是事实是, 如果你真的去编写一个巨大的 match...case 再用 objdump 去检查它编译出来的汇编代码, 会发现它底层"可能"是巨大的 if…else if…else 结构. 这样执行一次 match 的时间, 是要与 case 数成正比的. 注意: 优化到查表是编译器优化的一部分, 编译器能不能帮你优化你在写代码的时候是不知道的, 所以我用的是"可能".

还有另一点, 使用巨大的 match...case 语句, 可能会导致栈空间过大而 stack overflow, 例如你在 case 下定义变量, 那么每个 case 下变量使用的栈空间会被提前分配好, 即使你未进入对应的 case 分支. 

从经验来说, 如果 case 数目小于几十条, 那么用 match 或者 array/hashmap 查表等都不会有太大的问题; 一旦接近 100 条, 最好是采用 array 查表法.


我写了一个测试文件, 您可以自己跑一下查看效果

```rs

use std::ops::{Add, Div, Mul, Sub};


fn add<T>(a: T, b: T) -> T

where

    T: Add<Output = T>,

{

    a + b

}


fn sub<T>(a: T, b: T) -> T

where

    T: Sub<Output = T>,

{

    a - b

}


fn mul<T>(a: T, b: T) -> T

where

    T: Mul<Output = T>,

{

    a * b

}


fn div<T>(a: T, b: T) -> T

where

    T: Div<Output = T>,

{

    a / b

}


fn calculate_1<T>(a: T, b: T, op: usize) -> T

where

    T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Copy,

{

    match op {

        0 => add(a, b),

        1 => sub(a, b),

        ... // 请自行补齐一下

        254 => mul(a, b),

        255 => div(a, b),

        _ => unreachable!(),

    }

}


fn calculate_2<T>(a: T, b: T, op: usize, opList: &[fn(T, T) -> T]) -> T

where

    T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Copy,

{

    opList[op](a, b)

}


fn main() {

    let now = std::time::SystemTime::now();

    for i in 0..10000000 {

        calculate_1(3, 3, i % 256);

    }

    println!("{:?}", now.elapsed());


    let opList = [

        add::<u32>, sub::<u32>, mul::<u32>, div::<u32>, add::<u32>, sub::<u32>, mul::<u32>,

        ... // 请自行补齐一下

        add::<u32>, sub::<u32>, mul::<u32>, div::<u32>,

    ];

    let now = std::time::SystemTime::now();

    for i in 0..10000000 {

        calculate_2(3, 3, i % 256, &opList);

    }

    println!("{:?}", now.elapsed());

}

```

1
0

轻松实现Rust系统入门,实战编译器开发

入门者的平缓学习曲线,聚焦Rust核心重难点,获得实际应用能力

442 学习 · 45 问题

查看课程