rust 创建“def_union”宏以创建类似联合的枚举

cl25kdpy  于 2023-01-17  发布在  其他
关注(0)|答案(1)|浏览(122)

我想创建一个'def_union'宏,它创建一个带有From支持的类似 * union的 * 枚举。

macro_rules! def_union
{
    ($name:ident $(< $( $param:tt $( : $bound_lt0:tt $(+ $bound_lt:tt )* )? ),+ >)?
    {
        $($type_name:ident : $type:ty),*
    }) =>
    {
        enum $name $(< $( $param $( : $bound_lt0 $(+ $bound_lt )* )? ),+ >)?
        {
            $(
                $type_name($type)
            ),*
        }

        $(
            impl $(< $( $param:tt $( : $bound_lt0:tt $(+ $bound_lt:tt )* )? ),+ >)?
                From<$type> for $name $(< $( $param $( : $bound_lt0 $(+ $bound_lt )* )? ),+ >)?
            {
                fn from(value: $type) -> $name
                {
                    $name::$type_name(value)
                }
            }
        )*
    };
}

trait UnionValue {}

def_union!
(
    UnionType<Value0: UnionValue, Value1: UnionValue, String>
    {
        Value0: Value0,
        Value1: Value1,
        Other: String
    }
);

fn main()
{
    
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2c2f13988dc3b51431db4fe0b40a6706
不幸的是,输出为:

Compiling playground v0.0.1 (/playground)
error: meta-variable `param` repeats 1 time, but `r#type` repeats 3 times
  --> src/main.rs:15:10
   |
15 |           $(
   |  __________^
16 | |             impl $(< $( $param:tt $( : $bound_lt0:tt $(+ $bound_lt:tt )* )? ),+ >)?
17 | |                 From<$type> for $name $(< $( $param $( : $bound_lt0 $(+ $bound_lt )* )? ),+ >)?
18 | |             {
...  |
23 | |             }
24 | |         )*
   | |_________^

error: could not compile `playground` due to previous error

问题出在泛型参数上。我不知道解决方法。
编辑:为通用参数添加了鉴别器特征。

m1m5dgzv

m1m5dgzv1#

我将假设您想要解决错误,而不仅仅是实现特定的宏。
要解决这个错误,你可以选择使用帮助宏。这个技巧一开始并不明显,所以让我们来显示代码。(带注解)

macro_rules! def_union {
    (
        $name:ident$(<$($param_name:ident$(($($param_bounds:tt)*))?),+>)? {
            $($type_name:ident: $type:ty),*
        }
    ) => {
        enum $name $(<$($param_name$(: $($param_bounds)*)?),+>)? {
            $(
                $type_name($type)
            ),*
        }

        def_union!(@$name ($)
            ($(<$($param_name$(: $($param_bounds)*)?),+>)?)
            ($name $(<$($param_name),*>)?));

        $(
            $name!($type_name $type);
        )*
    };

    // here we generate helper macro that will break the repetition paradox.
    // all of the outer repeating parts are passed to later outputted macro
    // the `$t` is used as escape token that allows us to output new macro
    (@$name:ident ($t:tt) ($($generics:tt)*) ($($type:tt)*)) => {
        macro_rules! $name {
            ($t name:ident $t type:ty) => {
                impl$($generics)* From<$t type> for $($type)* {
                    fn from(value: $t type) -> Self {
                        Self::$t name(value)
                    }
                }
            };
        }
    };
}

trait UnionValue {}

// I removed generic parameters because they were conflicting each other.
// I also altered syntax a bit to simplify the macro, you can choose to
// make it more like rust syntax
def_union!(
    UnionType<Value0(UnionValue)> {
        Value0: Value0,
        Value2: usize
    }
);

fn main() {}

相关问题