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 } }; } #}