Более сжатая инициализация HashMap

Я использую HashMap для подсчета вхождений разных символов в строке:

let text = "GATTACA";
let mut counts: HashMap<char, i32> = HashMap::new();
counts.insert('A', 0);
counts.insert('C', 0);
counts.insert('G', 0);
counts.insert('T', 0);

for c in text.chars() {
    match counts.get_mut(&c) {
        Some(x) => *x += 1,
        None => (),
    }
}

Есть ли более сжатый или декларативный способ инициализации HashMap? Например, в Python я бы сделал:

counts = { 'A': 0, 'C': 0, 'G': 0, 'T': 0 }

или

counts = { key: 0 for key in 'ACGT' }

Ответы

Ответ 1

Вы можете использовать итераторы для эмуляции понимания словаря, например

let counts = "ACGT".chars().map(|c| (c, 0_i32)).collect::<HashMap<_, _>>();

или даже for c in "ACGT".chars() { counts.insert(c, 0) }.

Кроме того, можно написать макрос, чтобы обеспечить краткую инициализацию произвольных значений.

macro_rules! hashmap {
    ($( $key: expr => $val: expr ),*) => {{
         let mut map = ::std::collections::HashMap::new();
         $( map.insert($key, $val); )*
         map
    }}
}

используется как let counts = hashmap!['A' => 0, 'C' => 0, 'G' => 0, 'T' => 0];.

Ответ 2

Еще один способ, который я вижу в официальном документе: https://doc.rust-lang.org/std/collections/struct.HashMap.html

use std::collections::HashMap;

fn main() {
    let timber_resources: HashMap<&str, i32> =
    [("Norway", 100),
     ("Denmark", 50),
     ("Iceland", 10)]
     .iter().cloned().collect();
    // use the values stored in map
}