Я хотел бы использовать макрос для создания идентичных impl
блоков для нескольких конкретных типов. В настоящее время мой код выглядит примерно так:
macro_rules! impl_methods {
($ty:ty, { $($method:item);+} ) => {
impl $ty { $($method)+ }
};
($ty:ty, $($more:ty),+ {$($method:item);+}) => {
impl_methods!($ty, {$($method);+});
impl_methods!($($more),+, {$($method);+});
};
}
struct Hi;
struct Hello;
impl_methods!(Hi, Hello {
/// `true` if it works, good
fn works_good(&self) -> bool {
true
};
/// `true` if rustfmt is working
fn gets_rustfmt(&self) -> bool {
false
}
});
assert!(Hi.works_good() && Hello.works_good());
assert!(!(Hi.gets_rustfmt() | Hello.gets_rustfmt()));
Это работает достаточно хорошо (генерируются импы), но у него есть одна неприятная проблема; методы, определенные внутри макроса, не форматируются как rustfmt
.
Это небольшая проблема, но она достаточно раздражает, и мне интересно ее решение. Я знаю, что rustfmt отформатирует содержимое макроса, если это содержимое имеет некоторую форму (является выражением?), И поэтому, например, следующее содержимое макроса будет отформатировано:
macro_rules! fmt_me {
($inner:item) => {
$inner
};
}
fmt_me!(fn will_get_formatted() -> bool { true });
Итак, я надеясь , что есть какой-то способ, которым я могу написать свой макрос, например,
impl_methods!(Hi, Hello {
fmt_me!(fn my_method(&self) -> bool { true });
fmt_me!(fn my_other_method(&self) -> bool { false });
});
И чтобы каждый отдельный метод был покрыт rustfmt.
Возможно ли это? Есть ли какое-нибудь заклинание c магов, которое даст мне прекрасное форматирование, которое я хочу?
Ответ
Благодаря ответу ниже (от @ seiichi-uchida) я могу заставить это работать с следующий код:
macro_rules! impl_methods {
($ty:ty, { $($method:item)+} ) => {
impl $ty { $($method)+ }
};
($ty:ty, $($more:ty),+, {$($method:item)+}) => {
impl_methods!($ty, {$($method)+});
impl_methods!($($more),+, {$($method)+});
};
}
macro_rules! fmt_me {
($inner:item) => {
$inner
};
}
// called like:
impl_methods!(Hi, Hello, {
fmt_me!(fn this_is_a_method(&self) -> bool { true });
fmt_me!(fn this_is_another_method(&self) -> bool { true });
});