通过在RUST宏$(...)?中使用可选参数,我希望能够更改 struct 的构造方式.例如:

struct Field<T>(T);
struct OptionalField<T>(T);

define_struct!(StructName => {
  field_one: i32,
  field_two?: i32
});

// would ideally evaluate to

struct StructName {
  field_one: Field<i32>,
  field_two: OptionalField<i32>
}

然而,编写包含重复部分的宏并不是困难的部分,给我带来麻烦的部分是如何使可选问号更改用作 struct 的字段类型的类型.到目前为止,我已经try 了这个:

macro_rules! define_struct {
    ($name:ident => {
        $($field_name:ident$(?)?: $type:ty),*
    }) => {
        struct $name {
            $($field_name: $(Optional)?Field<$type>),*
        }
    };
}

宏调用很好,并且遵循定义的模式,但是在Field标识符前插入Optional是很困难的.部分$(Optional)?抛出错误:

attempted to repeat an expression containing no syntax variables matched as repeating at this depth
|
|  $($field_name: $(Optional)?Field<$type>),*
|                  ^^^^^^^^^^

有没有办法在不使用语法变量的情况下根据可选宏模式的存在来插入关键字?

推荐答案

你可以用incremental tt muncherpush-down accumulation做到这一点:

macro_rules! define_struct {
    (@fields $name:ident { $($fields:tt)* } $field_name:ident?: $type:ty, $($rest:tt)*) => {
        define_struct!(@fields
            $name {
                $($fields)*
                $field_name: OptionalField<$type>,
            }
            $($rest)*);
    };
    (@fields $name:ident { $($fields:tt)* } $field_name:ident: $type:ty, $($rest:tt)*) => {
        define_struct!(@fields
            $name {
                $($fields)*
                $field_name: Field<$type>,
            }
            $($rest)*);
    };
    (@fields $name:ident { $($fields:tt)* }) => {
        struct $name { $($fields)* }
    };
    
    ($name:ident => { $($fields:tt)* }) => {
        define_struct!(@fields $name {} $($fields)*);
    };
}

Playground

Rust相关问答推荐

无法在线程之间安全地发送future (&Q;)&错误

带扫描的铁 rust 使用滤镜

如何为 struct 字段设置新值并在Ruust中的可变方法中返回旧值

在使用AWS SDK for Rust时,如何使用硬编码访问密钥ID和密钥凭据?

我们能确定Rust会优化掉Clone()吗?如果它会立即掉落?

在铁 rust 中,如何一次只引用几件事中的一件?

Rust ndarray:如何从索引中 Select 数组的行

Rust面向对象设计模式

`actix-web` 使用提供的 `tokio` 运行时有何用途?

Option<&T> 如何实现复制

方法可以被误认为是标准特性方法

为什么 Rust 的临时值有时有参考性有时没有?

n 个范围的笛卡尔积

Rustlings 切片原语

当用作函数参数时,不强制执行与绑定的关联类型

将 (T, ()) 转换为 T 安全吗?

BigUint 二进制补码

相互调用的递归异步函数:检测到循环

Rust 注释会增加二进制大小吗?

`impl Trait` 返回类型导致错误的生命周期省略