#repeat #template #duplicate #macro #code

repeated

允许您多次重复代码块

3 个版本

0.1.2 2020 年 11 月 21 日
0.1.1 2020 年 11 月 18 日
0.1.0 2020 年 11 月 17 日

1279Rust 模式

每月 30 次下载

MIT 许可证

17KB
173

repeated

这是一个过程宏,允许您多次重复代码模板。

示例

从测试中

这将把从 0 到 255(包括)的每个值推入 vec v。

let mut v = Vec::<u32>::with_capacity(256);
repeated!(for z in [0;255] {
    v.push(%%z%%);
});
println!("{:?}", v);

在定义您的 for 循环来描述重复块之后,您可以传递一个字符串字面量来描述每个重复如何与前一个迭代连接。在这里,我们使用一个空的字符串字面量以保持每个重复相邻。我们首先创建一个值 n 的整数为 111,然后继续定义另一个重复块。第二个重复块在范围定义上有可选的第三个参数,表示我们应该增加的步长。

let n = repeated!(for _unused in [0;3] {1}, "");
repeated!(for i in [0;4;2] { println!("%%i%%"); }, "");
println!("Tested match position! Here is n: {}", n);

上一个块将打印以下内容

0
2
4
Tested match position! Here is n: 1111

以下示例演示了嵌套使用,其中块根据外部块的当前迭代重复可变次数

repeated!(for x in [0;9;3] {
    fn Welcome_%%x%%() {
        repeated!(for y in [1;%%x%%;2] {
            println!("From within the macro %%x%%:%%y%%!");
        });
    }
});
Welcome_3();

最后,有些情况下调用宏是不合法的。其中一种情况是在 match 分支位置。在下面的示例中,您可以看到即使尝试创建类似的 match 分支,也可以继续使用 repeated 宏。您可以为您的主体定义一个 preludepostlude。为了做到这一点,您必须提供一个标识符来表示您的 pre/post-lude。下面的示例提供了定义每个都使用标识符 my 的预定义和后定义的示例。

let t = 3;
repeated!(
    %% my prelude
    match t {
    prelude my %%
    for x in [0;15] {
        %%x%% => {
            println!("{}", repeated!(for y in [0;%%x%%] {%%x%%},""));
        }
    }
    %% my postlude
    _ => panic!(),
    }
    postlude my %%
);

这将打印 3333 到控制台。

性能

如果不小心,大量的重复可能会变得非常慢。最好逐渐增加重复次数到您想要的次数,而不是立即将重复次数设置为最终次数。如果您发现编译时间受到了严重影响,可能有用的是避免大型函数。例如,以下代码的编译时间非常长,可能会在某个时刻出错

repeated!(
    %%s prelude
    match x {
    prelude s%%
    for j in [0;255] {
        %%j%% => {
            repeated!(for i in [0;%%j%%] { println!("%%i%%"); });
        }
    }
    %%e postlude
        _ => {
            println!("No match was found!!");
        }
    }
    postlude e%%);

上面的代码创建了一个包含超过 32,000 个 println! 语句的 match 语句。将所有这些放在一个函数中可能会显著减慢编译器。相反,我们可以重构上面的代码到测试中的示例

repeated!(
    for j in [0;255] {
        fn repeat_%%j%%() {
            repeated!(for i in [0;%%j%%] { println!("%%i%%"); });
        }
    }
);

#[test]
fn large_expansions_are_still_performant() {
    let x = 128;
    repeated!(
        %%s prelude
        match x {
        prelude s%%
        for j in [0;255] {
            %%j%% => {
                repeat_%%j%%();
            }
        }
        %%e postlude
            _ => {
                println!("No match was found!!");
            }
        }
        postlude e%%);
}

我们仍然有嵌套的重复语句,但这次我们定义了单独的函数来执行 println!。重复匹配的分支现在不再包含数百行的代码,而是只包含对我们定义的一个函数的简单调用。这段代码的编译速度比之前的例子快得多。

贡献指南

测试和无警告/错误构建。

我希望改进在您定义了前言或后言的情况下错误处理,以便与没有它们时的错误处理相匹配。

另一个值得拥有的特性是支持迭代除了整数以外的其他数据。

依赖项

~3.5–4.5MB
~88K SLoC