hashmap!
#[macro_export]
macro_rules! hashmap {
(@single $($x:tt)*) => (());
(@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));
($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) };
($($key:expr => $value:expr),*) => {
{
let _cap = hashmap!(@count $($key),*);
let mut _map = ::std::collections::HashMap::with_capacity(_cap);
$(
let _ = _map.insert($key, $value);
)*
_map
}
};
}
-
宏属性:
-
#[macro_export]
:这个属性使得宏可以在定义它的 crate 外部使用。
-
-
内部辅助宏:
-
(@single $($x:tt)*) => (());
:这是一个内部宏规则,它匹配任何 Token 树(tt
)并返回一个空元组。这个规则似乎没有实际作用,可能是为了占位或调试。 -
(@count $($rest:expr),*) => (<[()]>::len(&[rest)),*]));
:这是另一个内部宏规则,用于计算宏调用中提供的表达式数量。它通过生成一个元组数组并计算其长度来实现。
-
-
外部宏规则:
-
(key:expr => (value),+) };
:这个规则处理以逗号结尾的键值对列表。它是一个重复规则,允许宏调用者提供多个键值对。 -
(key:expr => $value:expr),*) => { ... };
:这个规则处理不以逗号结尾的键值对列表。它计算键的数量,初始化一个具有适当容量的HashMap
,然后将每个键值对插入到HashMap
中。
-
-
HashMap 初始化:
-
let _cap = hashmap!(@count key),*);
:使用@count
内部宏规则来确定宏调用中提供的键的数量。 -
let mut _map = ::std::collections::HashMap::with_capacity(_cap);
:根据计算出的键的数量来初始化HashMap
的容量。 -
key, $value);)*
:遍历所有键值对,并将它们插入到HashMap
中。
-
使用示例:
use std::collections::HashMap;
fn main() {
let mut map = hashmap!(
"key1" => 1,
"key2" => 2,
"key3" => 3,
);
assert_eq!(map.len(), 3);
assert_eq!(map["key1"], 1);
assert_eq!(map["key2"], 2);
assert_eq!(map["key3"], 3);
}
执行上述宏调用. 首先匹配 ,
结尾的几个部分
"key1" => 1,
"key2" => 2,
"key3" => 3,
对每个部分,再次调用 hashmap!($($key => $value),+)
这一次调用的就不再包含 ,
,所以会去执行另一个分支
fn main(){
// let _cap = hashmap!(@count $($key),*);
// Note: 这里会调用内部辅助宏.
let _cap = hashmap!(@count "key1", "key2", "key3");
// let mut _map = ::std::collections::HashMap::with_capacity(_cap);
let mut _map= HashMap::with_capacity(_cap);
//$(
// let _ = _map.insert($key, $value);
//)*
// 重复执行三次上述片段
let _ = _map.insert("key1",1);
let _ = _map.insert("key2",2);
let _ = _map.insert("key3",3);
return _map
}
然后,对上述的执行结果,再次执行内部辅助宏 @count
(@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));
-
(<[()]>::len(&[$(hashmap!(@single $rest)),*])
是宏展开的代码。这里使用了 Rust 的数组和类型推断机制来计算参数的数量。-
<[()]>::len(&[...])
是一个类型推断的技巧,它创建了一个空元组()
的数组,并调用.len()
方法来获取数组的长度。 -
$(hashmap!(@single $rest)),*
是一个重复的宏调用,对于每个$rest
表达式,它都会调用hashmap!(@single ...)
宏。
-
最后的生成结果如下:
fn main() {
//let _cap = hashmap!(@count "key1", "key2", "key3");
let _cap = <[()]>::len(&[((),), ()]);
// _cap = 3
}
<[()]>
是用于类型推断的语法,它指示编译器去推断数组的类型。这里的 <[()]>
并不是指一个数组字面量,而是一种特殊的语法结构,称为类型参数推断(type hint)。
具体来说,<[()]>
告诉编译器,我们想要一个数组,其元素类型为 ()
(空元组),并且希望编译器根据上下文推断出数组的具体类型。在这个例子中,.len()
方法需要一个数组引用作为参数,而 <[()]>
就是用来提供这个数组引用的类型信息
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于