我可以重写这个macro_rules吗!宏以与 rustfmt 一起使用的方式吗?

cmy*_*myr 5 rust rust-macros

我想使用宏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()));

Run Code Online (Sandbox Code Playgroud)

这工作得很好(生成了 impl),但它有一个令人沮丧的问题;宏内部定义的方法不会被格式化rustfmt

这是一个小问题,但它很烦人,我很好奇解决方案。我知道 rustfmt 会格式化宏的内容,如果这些内容具有某种形式(是表达式?),因此例如以下宏的内容将被格式化:

macro_rules! fmt_me {
    ($inner:item) => {
        $inner
    };
}

fmt_me!(fn will_get_formatted() -> bool { true });
Run Code Online (Sandbox Code Playgroud)

所以我希望有某种方法可以编写我的宏,例如

macro_rules! fmt_me {
    ($inner:item) => {
        $inner
    };
}

fmt_me!(fn will_get_formatted() -> bool { true });
Run Code Online (Sandbox Code Playgroud)

并让 rustfmt 涵盖每个单独的方法。

这可能吗?有没有什么神奇的咒语可以给我我想要的可爱的格式?

回答

感谢下面的答案(来自@seiichi-uchida),我可以使用以下代码来完成此操作:

impl_methods!(Hi, Hello {
    fmt_me!(fn my_method(&self) -> bool { true });
    fmt_me!(fn my_other_method(&self) -> bool { false });
});
Run Code Online (Sandbox Code Playgroud)

Sei*_*ida 3

在最后一个类型和 impl 块之间添加一个逗号应该可以解决问题:

impl_methods!(Hi, Hello, {
    fmt_me!(fn my_method(&self) -> bool { true });
    fmt_me!(fn my_other_method(&self) -> bool { false });
});
Run Code Online (Sandbox Code Playgroud)

这将被格式化为:

 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
+        }
+    );
 });
Run Code Online (Sandbox Code Playgroud)

一般来说,rustfmt 只能格式化参数可以被解析为有效 Rust AST 节点的宏调用(有一些例外)。