在 Rust Hashmap 中插入元素時應該注意的事項

在對代碼進行優化時,如果想在 hashmap、hashset 或任何類似的結構中插入元素,需要注意一個事項。

你可能想在代碼中做以下一些事情:

use std::collections::HashMap;

fn main() {
    let mut map: HashMap<&str, u32> = HashMap::new();
    map.entry("poneyland").or_insert(3);

    assert_eq!(map["poneyland"], 3);
}

但是如果在插入時需要做更多的工作呢?可以這樣做:

map.entry("poneyland").or_insert(do_something);

這裏的問題是,如果鍵 “poneyland” 已經存在於 hashmap 中,do_something 仍然會被調用。如果 do_something 消耗時間或 CPU,那麼代碼的性能將會下降。

在這裏,你應該做的是使用 or_insert_with 方法,並像這樣傳遞一個閉包:

map.entry("poneyland").or_insert_with(|| {
    do_something()
};

這裏編寫了一些快速測試的代碼,以便你可以自己進行驗證:

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::{thread, time};

    fn compute_value_to_insert() -> usize {
        println!("My insertion function starts.");
        thread::sleep(time::Duration::from_secs(2));
        println!("My insertion function finished.");
        0
    }

    #[test]
    fn or_insert() {
        let mut h: HashMap<usize, usize> = HashMap::new();
        h.insert(0, 0);
        h.entry(0).or_insert(compute_value_to_insert());
    }

    #[test]
    fn or_insert_with() {
        let mut h: HashMap<usize, usize> = HashMap::new();
        h.insert(0, 0);
        h.entry(0).or_insert_with(|| compute_value_to_insert());
    }
}

當執行 or_insert 測試時,結果如下:

running 1 test
test tests::or_insert ... ok

test result: ok. 1 passed; 0 failed; finished in 2.00s

當執行 or_insert_with 測試時,結果如下:

running 1 test
test tests::or_insert_with ... ok

test result: ok. 1 passed; 0 failed; finished in 0.00s

從測試結果可以看出,當使用 or_insert 方法時,執行完成時間是 2 秒;當使用 or_insert_with 方法時,執行完成時間是近乎 0 秒。性能提升還是很明顯的。


本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/u8LDBtzaAJwx26odZb6j_A