Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 使用宏写入常量泛型枚举组合_Generics_Rust_Enums_Rust Macros - Fatal编程技术网

Generics 使用宏写入常量泛型枚举组合

Generics 使用宏写入常量泛型枚举组合,generics,rust,enums,rust-macros,Generics,Rust,Enums,Rust Macros,考虑一个具有两个常量泛型参数的玩具结构: pub struct Foo<const N: usize, const M: usize>([usize; N], [usize; M]); impl<const N: usize, const M: usize> Foo<N, M> { pub fn bar(&self) -> usize { N * M } } 我的问题是:我们是否可以编写一个声明性宏来生成它,而

考虑一个具有两个常量泛型参数的玩具结构:

pub struct Foo<const N: usize, const M: usize>([usize; N], [usize; M]);

impl<const N: usize, const M: usize> Foo<N, M> {
    pub fn bar(&self) -> usize {
        N * M
    }
}
我的问题是:我们是否可以编写一个声明性宏来生成它,而不必手动写出所有的组合?也就是说,类似于
impl\u foo\u enum!(1,2,3,4,5)
,而不是
impl\u foo\u enum!(1;1,1;2,1;3,[…等等])


我可以使用
粘贴
板条箱编写后一个宏:

macro_rules! impl_foo_enum {
    ($($n:literal;$m:literal),+) => {
        paste::paste! {
            pub enum FooEnum2 {
                $(
                    [<Foo _ $n _ $m>](Foo<$n, $m>)
                ),+
            }

            impl FooEnum2 {
                pub fn bar(&self) -> usize {
                    match self {
                        $(Self::[<Foo _ $n _ $m>](x) => x.bar()),+
                    }
                }
            }
        }
    }
}

impl_foo_enum!(1;1, 1;2, 2;1, 2;2);
macro\u规则!impl_foo_enum{
($($n:literal;$m:literal),+)=>{
粘贴:粘贴{
发布枚举FooEnum2{
$(
[](Foo)
),+
}
impl FooEnum2{
pub fn bar(&self)->使用{
匹配自我{
$(Self::[](x)=>x.bar())+
}
}
}
}
}
}
求你了!(1;1, 1;2, 2;1, 2;2);
()

为了得到不那么繁琐的宏,有几个相关的问题和有用的答案(,),我认为我可以适应,但在这两种情况下,函数调用都可以在宏中重复,这似乎简化了事情。例如,使用第一个链接示例中的方法,我开始:

macro_rules! for_all_pairs {
    ($mac:ident: $($x:literal)*) => {
        for_all_pairs!(@inner $mac: $($x)*; $($x)*);
    };
    (@inner $mac:ident: ; $($x:literal)*) => {};
    (@inner $mac:ident: $head:literal $($tail:literal)*; $($x:literal)*) => {
        $(
            $mac!($head $x);
        )*
        for_all_pairs!(@inner $mac: $($tail)*; $($x)*);
    };
}

macro_rules! impl_foo_enum {
    ($n:literal $m:literal) => {
        paste::paste! { [<Foo _ $n _ $m>](Foo<$n, $m>) }
    }
}

pub enum FooEnum3 {
    for_all_pairs!(impl_foo_enum: 1 2)
}
macro\u规则!适用于所有双{
($mac:ident:$($x:literal)*)=>{
对于所有对!(@internal$mac:$($x)*;$($x)*);
};
(@internal$mac:ident:;$($x:literal)*)=>{};
(@internal$mac:ident:$head:literal$($tail:literal)*;$($x:literal)*)=>{
$(
$mac!($head$x);
)*
对于所有对!(@internal$mac:$($tail)*;$($x)*);
};
}
宏规则!impl_foo_enum{
($n:literal$m:literal)=>{
粘贴::粘贴!{[](Foo)}
}
}
发布枚举FooEnum3{
对于所有对!(impl\u foo\u enum:1 2)
}
()

它不会编译,因为编译器不希望宏位于枚举变量位置(我相信)

(说清楚一点,我不一定要把上面的内容用于任何严肃的事情,我只是在实验时偶然发现了它,并感到好奇。)

你去:

#![允许(非案例类型)]
pub结构Foo([usize;N],[usize;M]);
impl-Foo{
pub fn bar(&self)->使用{
N*M
}
}
宏规则!impl_foo_2{
($($n:文字)*)=>{
执行2!([]@orig($($n)*)($($n)*)($($n)*)($($n)*));
};
(
[$($n:literal$m:literal))*]
@原版($($n_原版:文字)*)
($($n_未使用:文字)*)()
) => {
粘贴:粘贴{
发布枚举FooEnum2{
$([](Foo))+
}
impl FooEnum2{
pub fn bar(&self)->使用{
匹配自我{
$(Self::[](x)=>x.bar())+
}
}
}
}
};
(
[$($t:tt)*]
@原版($($n_原版:文字)*)
()($m0:literal$($m:literal)*)
) => {
求你了(
[$($t)*]
@原币($($n_原币)*)
($($n原)*)($($m)*)
);
};
(
[$($t:tt)*]
@原版($($n_原版:文字)*)
($n0:literal$($n:literal)*)($m0:literal$($m:literal)*)
) => {
求你了(
[$($t)*($n0$m0)]
@原币($($n_原币)*)
($($n)*)($m0$($m)*)
);
}
}
求你了!(1 2 3 4 5);
impl_foo_2
在内部生成两份相同的号码列表副本。然后,它继续一次处理一个
m
,将其与每个
n
(它通过反复切断第一个
n
)相结合。如果
n
-列表已用尽,它将重置
n
-列表,并删除第一个
m
。所有这些操作将一直执行,直到所有
n
m
都用尽为止

中间结果被收集到宏的第一个参数中,该参数最后被传递到
impl\u foo\u enum

macro_rules! for_all_pairs {
    ($mac:ident: $($x:literal)*) => {
        for_all_pairs!(@inner $mac: $($x)*; $($x)*);
    };
    (@inner $mac:ident: ; $($x:literal)*) => {};
    (@inner $mac:ident: $head:literal $($tail:literal)*; $($x:literal)*) => {
        $(
            $mac!($head $x);
        )*
        for_all_pairs!(@inner $mac: $($tail)*; $($x)*);
    };
}

macro_rules! impl_foo_enum {
    ($n:literal $m:literal) => {
        paste::paste! { [<Foo _ $n _ $m>](Foo<$n, $m>) }
    }
}

pub enum FooEnum3 {
    for_all_pairs!(impl_foo_enum: 1 2)
}
#![allow(non_camel_case_types)]
pub struct Foo<const N: usize, const M: usize>([usize; N], [usize; M]);
impl<const N: usize, const M: usize> Foo<N, M> {
    pub fn bar(&self) -> usize {
        N * M
    }
}

macro_rules! impl_foo_2{
    ($($n:literal)*) => {
        impl_foo_2!([] @orig($($n)*) ($($n)*) ($($n)*));
    };
    (
        [$(($n:literal $m:literal))*]
        @orig($($n_orig:literal)*)
        ($($n_unused:literal)*) ()
    ) => {
        paste::paste! {
            pub enum FooEnum2 {
                $([<Foo _ $n _ $m>](Foo<$n, $m>)),+
            }
            impl FooEnum2 {
                pub fn bar(&self) -> usize {
                    match self {
                        $(Self::[<Foo _ $n _ $m>](x) => x.bar()),+
                    }
                }
            }
        }
    };
    (
        [$($t:tt)*]
        @orig($($n_orig:literal)*)
        () ($m0:literal $($m:literal)*)
    ) => {
        impl_foo_2!(
            [$($t)*]
            @orig($($n_orig)*)
            ($($n_orig)*) ($($m)*)
        );
    };
    (
        [$($t:tt)*]
        @orig($($n_orig:literal)*)
        ($n0:literal $($n:literal)*) ($m0:literal $($m:literal)*)
    ) => {
        impl_foo_2!(
            [$($t)* ($n0 $m0)]
            @orig($($n_orig)*)
            ($($n)*) ($m0 $($m)*)
        );
    }
}

impl_foo_2!(1 2 3 4 5);