我想使用macro_rules!
实现一个结构,因为泛型需要大量的样板和特征搜寻。
有问题的结构内部有一个哈希表,但是键和值类型将由用户提供。代码如下:
macro_rules! new_ytz {
($T: ty) => {
// define the struct
pub struct Ytz {
table: hashbrown::hash_map::HashMap<$T, $T>,
}
impl Ytz {
pub fn new() -> Self {
Ytz {
table: hashbrown::hash_map::HashMap::<$T, $T>::new(),
}
}
pub fn add(&mut self, item: &$T) {
if self.table.contains_key(item) {
*self.table.get_mut(item).unwrap() += *item;
} else {
self.table.insert(*item, *item);
}
}
pub fn largest(&self) -> $T {
let mut result = 0;
for v in self.table.values() {
if result < *v {
result = *v;
}
}
result
}
}
// construct an instance of the struct and return it
Ytz::new()
};
}
// driver
fn main() {
let mut y = new_ytz!(u64); // should construct the object and return Ytz::new()
y.add(&71);
y.add(&25);
y.add(&25);
y.add(&25);
y.add(&34);
println!("{}", y.largest());
}
由于它试图将结构粘贴到主函数中,因此无法编译:
error: expected expression, found keyword `pub`
--> src/main.rs:4:9
|
4 | pub struct Ytz {
| ^^^ expected expression
...
40 | let mut y = new_ytz!(u64); // should construct the object and return Ytz::new()
| ------------- in this macro invocation
我该如何解决?如何将结构与impl
块一起公开粘贴到主函数之外?
答案 0 :(得分:1)
泛型需要很多样板
use std::collections::HashMap;
use core::hash::Hash;
use std::ops::AddAssign;
struct YtzU64<T: Eq + Ord + Hash + Copy + AddAssign> {
table: HashMap<T, T>
}
impl<T: Eq + Ord + Hash + Copy + AddAssign> YtzU64<T> {
pub fn new() -> Self {
Self {
table: HashMap::new()
}
}
pub fn add(&mut self, item: &T) {
if let Some(item) = self.table.get_mut(item) {
*item += *item;
} else {
self.table.insert(*item, *item);
}
}
pub fn largest(&self) -> Option<T> {
let mut values = self.table.values();
let mut largest:Option<T> = values.next().map(|t| *t);
for v in values {
if largest < Some(*v) {
largest = Some(*v);
}
}
largest
}
}
fn main() {
let mut y = YtzU64::new();
y.add(&71);
y.add(&25);
y.add(&25);
y.add(&25);
y.add(&34);
println!("{}", y.largest().unwrap());
}
我对宏的翻译需要比您的宏更少的样板。它减少了两个缩进,减少了4行(macro_rules !,顶部是模式匹配,最后是两个大括号)。请注意,我稍微更改了api,因为largest
现在返回了Option
,以匹配std::iter::Iterator::max()
。另请注意,您的api设计仅限于T:Copy
。如果要支持T: ?Copy + Clone
或T: ?Copy + ?Clone
,则必须重新设计它。
特质狩猎
编译器是您的朋友。观看当我删除一个特征边界时会发生什么
error[E0277]: the trait bound `T: std::hash::Hash` is not satisfied
...
使用宏是一个有趣的练习,但是使用宏重新实现泛型没有用。