Macros

1. Readme

宏是 Rust 程序员工具箱中的一个强大工具,要想对它有个简单认知,可以看看宏例子。让我们写一个!

问题陈述

你可以用vec![]内联宏,生产一个任意长度的Vec。然而,Rust 并没有生产HashMap的内联宏hashmap!()

例如,您的库的用户可能会编写hashmap!('a' => 3, 'b' => 11, 'z' => 32)。这应该扩展到以下代码:


# #![allow(unused_variables)]
#fn main() {
{
   let mut hm = HashMap::new();
   hm.insert('a', 3);
   hm.insert('b', 11);
   hm.insert('z', 32);
   hm
}
#}

注意maplit箱子时提供了一个很好地解决这个问题的宏。但请执行您自己的解决方案,而不是使用这个箱子,请在查看箱子源代码之前,自己尝试下。

资源

Peter Goodspeed-Niklaus

2. 开始你的表演

#[macro_export]
macro_rules! hashmap {
   () => {
       unimplemented!()
   };
}

3. 测试代码查看


# #![allow(unused_variables)]
#fn main() {
#[macro_use]
use std::collections::HashMap;

#[test]
fn test_empty() {
   let expected: HashMap<u32, u32> = HashMap::new();
   let computed: HashMap<u32, u32> = hashmap!();
   assert_eq!(computed, expected);
}

#[test]
//#[ignore]
fn test_no_trailing_comma() {
   let mut expected = HashMap::new();
   expected.insert(1, "one");
   expected.insert(2, "two");
   assert_eq!(hashmap!(1 => "one", 2 => "two"), expected);
}

#[test]
//#[ignore]
fn test_trailing_comma() {
   let mut expected = HashMap::new();
   expected.insert('h', 89);
   expected.insert('a', 1);
   expected.insert('s', 19);
   expected.insert('h', 8);
   assert_eq!(
       hashmap!(
           'h' => 89,
           'a' => 1,
           's' => 19,
           'h' => 8,
       ),
       expected
   );
}

#[test]
//#[ignore]
fn test_nested() {
   let mut expected = HashMap::new();
   expected.insert("non-empty", {
       let mut subhashmap = HashMap::new();
       subhashmap.insert(23, 623);
       subhashmap.insert(34, 21);
       subhashmap
   });
   expected.insert("empty", HashMap::new());
   assert_eq!(
       hashmap!(
           "non-empty" => hashmap!(
               23 => 623,
               34 => 21
           ),
           "empty" => hashmap!()
       ),
       expected
   );
}

mod test {
   #[test]
   //#[ignore]
   fn type_not_in_scope() {
       let _expected: ::std::collections::HashMap<(), ()> = hashmap!();
   }
}

#}

4. 答案


# #![allow(unused_variables)]
#fn main() {
// Ignoring the README's injunction, this is heavily based on the implementation from maplit.
// Original source is at https://github.com/bluss/maplit/blob/master/src/lib.rs#L27-L60

#[macro_export]
macro_rules! hashmap {
   ($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) };
   ($($key:expr => $value:expr),*) => {
       {
           let mut _map = ::std::collections::HashMap::new();
           $(
               _map.insert($key, $value);
           )*
           _map
       }
   };
}

#}



填充/相关