我可以重写这个 macro_rules 吗!宏以一种与 rustfmt 一起工作的方式?
Can I rewrite this macro_rules! macro in a way that works with rustfmt?
我想使用宏为多个具体类型生成相同的 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()));
这很好用(生成了 impl)但它有一个令人沮丧的问题;宏内定义的方法未按 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 涵盖每个单独的方法。
这可能吗?有什么神奇的咒语可以给我想要的可爱格式吗?
回答
感谢下面的回答(来自@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 });
});
在最后一个类型和 impl 块之间添加一个逗号应该可以解决问题:
impl_methods!(Hi, Hello, {
fmt_me!(fn my_method(&self) -> bool { true });
fmt_me!(fn my_other_method(&self) -> bool { false });
});
这将被格式化为:
impl_methods!(Hi, Hello, {
- fmt_me!(fn my_method(&self) -> bool { true });
- fmt_me!(fn my_other_method(&self) -> bool { false });
+ fmt_me!(
+ fn my_method(&self) -> bool {
+ true
+ }
+ );
+ fmt_me!(
+ fn my_other_method(&self) -> bool {
+ false
+ }
+ );
});
一般来说,rustfmt 只能格式化其参数可以被解析为有效 Rust AST 节点的宏调用(有一些例外)。
我想使用宏为多个具体类型生成相同的 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()));
这很好用(生成了 impl)但它有一个令人沮丧的问题;宏内定义的方法未按 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 涵盖每个单独的方法。
这可能吗?有什么神奇的咒语可以给我想要的可爱格式吗?
回答
感谢下面的回答(来自@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 });
});
在最后一个类型和 impl 块之间添加一个逗号应该可以解决问题:
impl_methods!(Hi, Hello, {
fmt_me!(fn my_method(&self) -> bool { true });
fmt_me!(fn my_other_method(&self) -> bool { false });
});
这将被格式化为:
impl_methods!(Hi, Hello, {
- fmt_me!(fn my_method(&self) -> bool { true });
- fmt_me!(fn my_other_method(&self) -> bool { false });
+ fmt_me!(
+ fn my_method(&self) -> bool {
+ true
+ }
+ );
+ fmt_me!(
+ fn my_other_method(&self) -> bool {
+ false
+ }
+ );
});
一般来说,rustfmt 只能格式化其参数可以被解析为有效 Rust AST 节点的宏调用(有一些例外)。