如何创建HashMap文字?

Max*_*kiy 55 hashmap rust

如何在Rust中创建HashMap文字?在Python中,我可以这样做:

hashmap = {
   'element0': {
       'name': 'My New Element',
       'childs': {
           'child0': {
               'name': 'Child For Element 0',
               'childs': {
                   ...
               }
           }
       }
   },
   ...
}
Run Code Online (Sandbox Code Playgroud)

在Go中这样:

type Node struct {
    name string
    childs map[string]Node
}

hashmap := map[string]Node {
    "element0": Node{
        "My New Element",
        map[string]Node {
            'child0': Node{
                "Child For Element 0",
                map[string]Node {}
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 59

Rust中没有地图文字语法.我不知道确切的原因,但我相信这一事实,有其作用maplike(如既多个数据结构BTreeMapHashMap)将使它很难挑选一个.

但是,您可以创建一个宏来为您完成工作,如为什么这个生锈的HashMap宏不再起作用?.这个宏被简化了一点,并且有足够的结构使它可以在游乐场中运行:

macro_rules! map(
    { $($key:expr => $value:expr),+ } => {
        {
            let mut m = ::std::collections::HashMap::new();
            $(
                m.insert($key, $value);
            )+
            m
        }
     };
);

fn main() {
    let names = map!{ 1 => "one", 2 => "two" };
    println!("{} -> {:?}", 1, names.get(&1));
    println!("{} -> {:?}", 10, names.get(&10));
}
Run Code Online (Sandbox Code Playgroud)

  • 在`grabbag_macros`箱子里也有一个.你可以在这里看到来源:https://github.com/DanielKeep/rust-grabbag/blob/master/grabbag_macros/src/lib.rs#L3-L64. (6认同)
  • 啊,真可惜 我喜欢Swift的方法,它可以从类型中提取文字。可以使用[`DictionaryLiteral`](https://developer.apple.com/documentation/swift/dictionaryliteral)初始化符合[`ExpressibleByDictionaryLiteral`](https://developer.apple.com/documentation / swift / expressiblebydictionaryliteral)(即使标准库提供了一种此类类型,[`Dictionary`](https://developer.apple.com/documentation/swift/dictionary)) (3认同)
  • 值得一提的是 Rust 1.56 的 `HashMap::from([ ("k1",1), ("k2",2) ])` (2认同)

Dan*_*ger 30

从 Rust 1.56 开始,您可以使用 初始化 HashMap from(),这有点像拥有 HashMap 文字。 from()接受一个键值对数组。你可以这样使用它:

use std::collections::HashMap;

fn main() {
    let hashmap = HashMap::from([
        ("foo", 1),
        ("bar", 2)
    ]);
}
Run Code Online (Sandbox Code Playgroud)


Dav*_* J. 26

我推荐maplit箱子.

引用文档:

具有特定类型的容器文字的宏.

#[macro_use] extern crate maplit;

let map = hashmap!{
    "a" => 1,
    "b" => 2,
};
Run Code Online (Sandbox Code Playgroud)

maplit crate对映射宏使用=>语法.由于语法上常规macro_rules的限制,不可能使用:as separator作为分隔符!宏.

请注意,生锈宏很灵活,您可以使用哪些括号进行调用.您可以将它们用作hashmap!{}或hashmap![]或hashmap!().这个箱子建议{}作为map&set宏的约定,它匹配它们的Debug输出.

btreemap从键值对列表中创建BTreeMap

btreeset从元素列表中创建BTreeSet.

hashmap从键值对列表中创建HashMap

hashset从元素列表中创建HashSet.

  • 从 Rust 1.56 开始,您无需外部创建即可执行此操作。`让 hm = HashMap::from([(1, "2"), (3, "4")]);` (3认同)

jup*_*p0r 24

有一个如何在文档中HashMap实现此目的的示例:

 let timber_resources: HashMap<&str, i32> =
    [("Norway", 100),
     ("Denmark", 50),
     ("Iceland", 10)]
    .iter().cloned().collect();
Run Code Online (Sandbox Code Playgroud)

  • 通过使用 `vec![ (name, value) ].into_iter().collect()` 可以调整此示例以避免这些问题 (13认同)
  • 虽然它适用于这种情况,但当使用类似`String`而不是`&str`的​​东西时,它会变得不必要地昂贵. (3认同)
  • 当然存在运行时成本,但也存在与添加其他板条箱依赖项或定义难以理解的宏相关的成本。大多数代码不是对性能至关重要的,我发现此版本可读性强。 (2认同)
  • 此外,这不适用于非克隆类型。 (2认同)
  • @Stargateur 因为我不做过早的优化,你也不应该。您的程序可能会受益于更优化的 HashMap 文字初始化,但也可能不会。如果您想获得最佳性能,请测量并优化程序中关键路径上的部分。随机优化东西只是一个糟糕的策略。我的回答对99.9999%的人来说都可以。它可读、编译速度快,不会引入会增加复杂性并引入潜在安全漏洞的依赖项。 (2认同)
  • 是的,像 hashmap![("Norway",100)] 这样的语法会让事情更具可读性,并且绝对不会是一种“过早的优化”。写得更短了!我认为它确实应该在标准库中。 (2认同)

Kam*_*šík 8

正如@Johannes 在评论中指出的那样,可以使用,vec![]因为:

  • Vec<T>实现IntoIterator<T>特征
  • HashMap<K, V> 工具 FromIterator<Item = (K, V)>

这意味着你可以这样做:

let map: HashMap<String, String> = vec![("key".to_string(), "value".to_string())]
    .into_iter()
    .collect();
Run Code Online (Sandbox Code Playgroud)

您可以使用,&str但如果不是,则可能需要注释生命周期'static

let map: HashMap<&str, usize> = vec![("one", 1), ("two", 2)].into_iter().collect();
Run Code Online (Sandbox Code Playgroud)


Pet*_*all 5

您可以使用velcro箱子*。它类似于maplit其他答案中推荐的,但具有更多的集合类型、更好的语法(至少在我看来!)和更多功能。

假设您想使用Strings 而不是&str,您的确切示例将如下所示:

use std::collections::HashMap;
use velcro::hash_map;

struct Node {
    name: String
    children: HashMap<String, Node>,
}

let map = hash_map! {
    String::from("element0"): Node {
        name: "My New Element".into(),
        children: hash_map! {
            String::from("child0"): Node {
                name: "child0".into(),
                children: hash_map!{}
            }
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

String由于s 的构造方式,这有点难看。但它可以变得更简洁,无需更改密钥类型,通过使用hash_map_from!它会自动进行转换:

use std::collections::HashMap;
use velcro::{hash_map, hash_map_from};

let map: HashMap<String, Node> = hash_map_from! {
    "element0": Node {
        name: "My New Element".into(),
        children: hash_map_from! {
            "child0": Node {
                name: "child0".into(),
                children: hash_map!{}
            }
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

这并不比 Go 版本更冗长


*全面披露:我是这个箱子的作者。