Macros 笛卡尔乘积匹配

Macros 笛卡尔乘积匹配,macros,nested,rust,match,repeat,Macros,Nested,Rust,Match,Repeat,我有两组不完整的类型(即结构名称、缺少泛型参数和生存期),我需要为每一对可能的组合执行一些代码: // these are my types struct A<T> { ... } struct B<'a, 'b, T> { ... } struct C { ... } struct X<T> { ... } struct Y { ... } struct W<'a> { ... } struct Z<T, D> { ... } /

我有两组不完整的类型(即结构名称、缺少泛型参数和生存期),我需要为每一对可能的组合执行一些代码:

// these are my types
struct A<T> { ... }
struct B<'a, 'b, T> { ... }
struct C { ... }

struct X<T> { ... }
struct Y { ... }
struct W<'a> { ... }
struct Z<T, D> { ... }

// this is the code I need to generate
match (first_key, second_key) {
    ("a", "x") => { ... A ... X ... }
    ("a", "y") => { ... A ... Y ... }
    ("a", "w") => { ... A ... W ... }
    ("a", "z") => { ... A ... Z ... }
    ("b", "x") => { ... B ... X ... }
    ("b", "y") => { ... B ... Y ... }
    // ...
}
但是我在产品匹配方面失败了,因为我已经在上面工作了几个小时。我找不到任何简单的方法来嵌套重复;我认为唯一的解决方案是使用宏将匹配案例列表转换为嵌套的值元组,然后对它们进行递归,但我发现这很难实现

另一个选择是使用构建脚本生成大的
匹配的代码,但是这个解决方案听起来相当脏


对于我错过的这个问题,有什么简单的解决办法吗?有没有简单的方法来实现
产品匹配?如何实现我的逻辑?

我认为您使用宏实现笛卡尔产品的想法是最好的

我不太确定您想要的
匹配
表达式是什么,因此我有一个重复的函数调用。但是,宏管道应该大致相同。希望你能从这里开始

macro_rules! cp_inner {
    ($f: expr, $x: expr, [$($y: expr),*]) => {
        $($f($x, $y);)*
    }
}

macro_rules! cartesian_product {
    ($f: expr, [$($x: expr),*], $ys: tt) => {
        $(cp_inner!($f, $x, $ys);)*;
    }
}

fn print_pair(x: u32, y: &'static str) {
    println!("({}, {})", x, y);
}

pub fn main() {
    cartesian_product!(print_pair, [1, 2, 3], ["apple", "banana", "cherry"]);
}
是一个宏
cartesian\u match
,可按如下方式使用:

fn main() {
    macro_rules! test( ($x: tt, $y: tt, $z: tt,) => {
        println!("{:?} {:?} {:?}", $x, $y, $z);
    });
    #[derive(Debug)]
    enum E {
        V1, V2, V3,
    }
    let b = false;
    let oi = Some(6);
    let e = E::V1;
    cartesian_match!(
        test,
        match (oi) {
            Some(n) => {format!("{} is the number", n)},
            None => {None as Option<usize>},
        },
        match (b) {
            true => true,
            false => {E::V3},
        },
        match (e) {
            E::V1 => true,
            E::V2 => 'l',
            E::V3 => 2,
        },
    );
}
macro_rules! cartesian_match(
    (
        $macro_callback: ident,
        $(match ($e: expr) {
            $($x: pat => $y: tt,)*
        },)*
    ) => {
        cartesian_match!(@p0,
            $macro_callback,
            (),
            $(match ($e) {
                $($x => $y,)*
            },)*
        )
    };
    (@p0,
        $macro_callback: ident,
        $rest_packed: tt,
        match ($e: expr) {
            $($x: pat => $y: tt,)*
        },
        $(match ($e2: expr) {
            $($x2: pat => $y2: tt,)*
        },)*
    ) => {
        cartesian_match!(@p0,
            $macro_callback,
            (
                match ($e) {
                    $($x => $y,)*
                },
                $rest_packed,
            ),
            $(match ($e2) {
                $($x2 => $y2,)*
            },)*
        )
    };
    (@p0,
        $macro_callback: ident,
        $rest_packed: tt,
    ) => {
        cartesian_match!(@p1,
            $macro_callback,
            @matched{()},
            $rest_packed,
        )
    };
    (@p1,
        $macro_callback: ident,
        @matched{$matched_packed: tt},
        (
            match ($e: expr) {
                $($x: pat => $y: tt,)*
            },
            $rest_packed: tt,
        ),
    ) => {
        match $e {
            $($x => cartesian_match!(@p1,
                $macro_callback,
                @matched{ ($matched_packed, $y,) },
                $rest_packed,
            ),)*
        }
    };
    (@p1,
        $macro_callback: ident,
        @matched{$matched_packed: tt},
        (),
    ) => {
        cartesian_match!(@p2,
            $macro_callback,
            @unpacked(),
            $matched_packed,
        )
        //$macro_callback!($matched_packed)
    };
    (@p2,
        $macro_callback: ident,
        @unpacked($($u: tt,)*),
        (
            $rest_packed: tt,
            $y: tt,
        ),
    ) => {
        cartesian_match!(@p2,
            $macro_callback,
            @unpacked($($u,)* $y,),
            $rest_packed,
        )
    };
    (@p2,
        $macro_callback: ident,
        @unpacked($($u: tt,)*),
        (),
    ) => {
        $macro_callback!($($u,)*)
    };
);
它接受数量可变的
match
项,并以嵌套方式逐个展开它们。它在不同的“内部阶段”(由宏参数列表中的
@
-前缀参数表示)中执行此操作:

  • 阶段
    @p0
    获取
    match
    e的列表,并将其转换为单个
    tt
    。本质上,它将
    match_1,match_2,match_3,
    转换为类似
    (match_1,(match_2,(match_3,(),)
    )。(这样做是为了防止“不一致的锁步迭代”。)
  • 阶段
    @p1
    解压
    @p0
    生成的内容,并将其转换为嵌套的
    匹配
    语句。它使用与
    @p0
    相同的技巧来存储与当前嵌套深度匹配的元素
  • 阶段
    @p2
    解压
    @p1
    生成的对象(即,它本质上将
    (((),v3),v2),v1,)
    转换为
    v1,v2,v3
    ,并将其传递到指定的回调

哎哟,看起来很痛:(祝你好运。我相信这个问题可以用宏很容易地解决——宏不会给Rust的功能增加任何真正的魔力,它们只是删除了样板。但是,你没有给我们展示样板。相反,你用
省去了问题的实质。我很确定你不想让我们创建一个macro扩展为literal
,但我们不知道它应该是什么。请查看如何创建。我首先提供2组2种类型的完整定义和匹配的所需完整代码。@Shepmaster by
…a…X…
我的意思是
f(A,X)
我认为这是一个最小的、完整的和可验证的例子。在我的具体案例中,我需要创建一个通道来传输与由
$first
实现的特征相关联的类型,然后启动一个线程,在该线程中实例化
$second
,并将其传递给一个函数(
f1
),然后调用一个函数(
f2
)在主线程上的
$first
上。
f2
要求
$first
实现一个trait,其泛型参数必须是
$second
的trait实现的关联类型,
f1
要求
$second
的trait实现。我想我们不同意可验证的含义,因为我无法用h根据我目前的理解,无论是否使用宏,您都不可能编写您所要求的代码。如果您希望您的问题显示
a
B
Z
,则
匹配
a、Z
B、Z
和a f的完整定义从宏调用的函数签名,然后我们可能可以看到样板文件,然后构造宏。
macro_rules! cartesian_match(
    (
        $macro_callback: ident,
        $(match ($e: expr) {
            $($x: pat => $y: tt,)*
        },)*
    ) => {
        cartesian_match!(@p0,
            $macro_callback,
            (),
            $(match ($e) {
                $($x => $y,)*
            },)*
        )
    };
    (@p0,
        $macro_callback: ident,
        $rest_packed: tt,
        match ($e: expr) {
            $($x: pat => $y: tt,)*
        },
        $(match ($e2: expr) {
            $($x2: pat => $y2: tt,)*
        },)*
    ) => {
        cartesian_match!(@p0,
            $macro_callback,
            (
                match ($e) {
                    $($x => $y,)*
                },
                $rest_packed,
            ),
            $(match ($e2) {
                $($x2 => $y2,)*
            },)*
        )
    };
    (@p0,
        $macro_callback: ident,
        $rest_packed: tt,
    ) => {
        cartesian_match!(@p1,
            $macro_callback,
            @matched{()},
            $rest_packed,
        )
    };
    (@p1,
        $macro_callback: ident,
        @matched{$matched_packed: tt},
        (
            match ($e: expr) {
                $($x: pat => $y: tt,)*
            },
            $rest_packed: tt,
        ),
    ) => {
        match $e {
            $($x => cartesian_match!(@p1,
                $macro_callback,
                @matched{ ($matched_packed, $y,) },
                $rest_packed,
            ),)*
        }
    };
    (@p1,
        $macro_callback: ident,
        @matched{$matched_packed: tt},
        (),
    ) => {
        cartesian_match!(@p2,
            $macro_callback,
            @unpacked(),
            $matched_packed,
        )
        //$macro_callback!($matched_packed)
    };
    (@p2,
        $macro_callback: ident,
        @unpacked($($u: tt,)*),
        (
            $rest_packed: tt,
            $y: tt,
        ),
    ) => {
        cartesian_match!(@p2,
            $macro_callback,
            @unpacked($($u,)* $y,),
            $rest_packed,
        )
    };
    (@p2,
        $macro_callback: ident,
        @unpacked($($u: tt,)*),
        (),
    ) => {
        $macro_callback!($($u,)*)
    };
);