I want to implement a struct using macro_rules!
because the generics require a lot of boilerplate and trait hunting.
The struct in question has a hash table inside but the key and the value types are to be provided by the user. The code is as follows:
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());
}
This won't compile since it tries to paste the struct within the main function:
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
How can I work around it? How can I paste the struct outside the main function publicly, along with the impl
block?
My translation of your macro requires less boilerplate than your macro. It has two fewer indents, 4 fewer lines (macro_rules!, pattern matching at the top, two close braces at the end). Note that I changed the api slightly, as
largest
now returns anOption
, to matchstd::iter::Iterator::max()
. Also note that your api design is limited toT:Copy
. You would have to redesign it a little if you want to supportT: ?Copy + Clone
orT: ?Copy + ?Clone
.The compiler is your friend. Watch what happens when I remove one of the trait bounds
Using a macro is an interesting exercise, but re-implementing generics using macros is not useful.