简体   繁体   English

您可以在没有语法变量的 rust 宏中使用可选参数吗?

[英]Can you use an optional argument in a rust macro without syntax variables?

Using an optional argument inside a rust macro $(...)?在 rust 宏$(...)? I'd like to be able to change how a struct is formulated.我希望能够改变结构的制定方式。 For example:例如:

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>
}

Writing a macro with repeated sections isn't the difficult part however, the part that's giving me trouble is how I can make the optional question mark change the type used as the struct's field type.编写带有重复部分的宏并不是困难的部分,但给我带来麻烦的部分是如何使可选问号更改用作结构字段类型的类型。 So far I've tried this:到目前为止,我已经尝试过:

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

The macro invocation is fine and follows the defined pattern however inserting the Optional before the Field identifier is what's proving difficult.宏调用很好,并且遵循定义的模式,但是在Field标识符之前插入Optional是困难的。 The section $(Optional)? $(Optional)? throws the error:抛出错误:

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

Is there any way to insert a keyword depending upon the presence of an optional macro pattern without having to use a syntax variable?有没有办法根据可选宏模式的存在插入关键字而不必使用语法变量?

You can do it with an incremental tt muncher and push-down accumulation :您可以通过增量tt muncher下推累积来做到这一点:

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 操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM