#repetitive #duplicate #repeat #code #multiple

akin

A crate 用于更轻松、更快速地编写重复代码

14 个版本

0.4.0 2023 年 1 月 3 日
0.3.3 2022 年 3 月 28 日
0.2.3 2022 年 3 月 8 日
0.1.4 2022 年 3 月 5 日

#1526 in 开发工具

Download history 11/week @ 2024-03-14 26/week @ 2024-03-21 29/week @ 2024-03-28 10/week @ 2024-04-04 7/week @ 2024-04-11 8/week @ 2024-04-18 1/week @ 2024-04-25 2/week @ 2024-05-16 29/week @ 2024-05-23 1278/week @ 2024-05-30 1520/week @ 2024-06-06 805/week @ 2024-06-13 1274/week @ 2024-06-20 1518/week @ 2024-06-27

5,475 下载/每月
profi 中使用

MIT 许可证

26KB
282

akin

A zero-dependency crate for writing repetitive code easier and faster

Tests Crates.io

查看 语法 了解如何使用它。

  1. 为什么?
  2. 示例
  3. 语法
  4. NONE
  5. 联合修饰符
  6. 零依赖?真的吗?

为什么?

我发现自己不得不写很多重复的代码(主要是解析时匹配枚举)。
神奇的 duplicate 对我来说语法不直观,所以我决定制作自己的工具。

示例

trait Sqrt {
    fn dumb_sqrt(self) -> Result<f64, &'static str>;
}

akin! {
    let &int_type = [i64, u64];
    let &negative_check = [
        {
            if self < 0 {
                return Err("Sqrt of negative number")
            }
        }, 
        NONE
    ];
    
    let &num = [1,     2,    3,  4];
    let &res = [1., 1.41, 1.73,  2.];
    let &branch = {
        *num => Ok(*res),
    };
    
    impl Sqrt for *int_type {
        fn dumb_sqrt(self) -> Result<f64, &'static str> {
            *negative_check
            
            match self {
                *branch
                _ => Err("Sqrt of num not in [1, 4]")
            }
        }
    }
}

它被扩展为

trait Sqrt {
    fn dumb_sqrt(self) -> Result<f64, &'static str>;
}

impl Sqrt for i64 {
    fn dumb_sqrt(self) -> Result<f64, &'static str> {
        if self < 0 {
            return Err("Sqrt of negative number")
        }
        
        match self {
            1 => Ok(1.),
            2 => Ok(1.41),
            3 => Ok(1.73),
            4 => Ok(2.),
            _ => Err("Sqrt of num not in [1, 4]")
        }
    }
}

impl Sqrt for u64 {
    fn dumb_sqrt(self) -> Result<f64, &'static str> {
        match self {
            1 => Ok(1.),
            2 => Ok(1.41),
            3 => Ok(1.73),
            4 => Ok(2.),
            _ => Err("Sqrt of num not in [1, 4]")
        }
    }
}

akin 的好处在于它可以自动检测每个变量在每个作用域中的值的数量,例如,“branch”将被复制 4 次(因为“num”和“res”都有 4 个值),但主函数只复制一次,因为它所拥有的所有变量都有 2 个值。

请查看存储库中的 tests/ 文件夹以获取更多示例。

语法

该软件包只提供一个宏,akin!。语法如下

首先,声明你将使用的变量。变量名必须以 & 开头,因为这是它区分宏或真实声明的唯一方法。
请注意,变量以 ; 结尾。

let &variable = [v1, v2, v3, ...];
let &variable2 = [...];
    
let &code = {
    ...
};

然后,当所有变量都已声明后,您可以编写要复制的代码片段。
复制的次数取决于使用的变量。

let &lhs = [1, 2, 3];
let &rhs = [4, 5, 6];
println!("*lhs + *rhs = {}", *lhs + *rhs);

将被扩展为

println!("1 + 4 = {}", 1 + 4);
println!("2 + 5 = {}", 2 + 5);
println!("3 + 6 = {}", 3 + 6);

因为变量 &lhs&rhs 都有 3 个值。

如你所见,& 用于声明变量,而 * 用于“解引用”到当前值。

为了方便,在声明变量时也接受范围语法,例如:0..30..=3,它们分别等同于 [0,1,2][0,1,2,3]。因此,上述示例也可以写成:

let &lhs = 1..=3;
let &rhs = 4..=6;
println!("*lhs + *rhs = {}", *lhs + *rhs);

目前,只有能适应 u64 的无符号整数才支持在范围中使用,例如 -10..-1'a'..'c',这在常规 Rust 中是可以的,但在 akin 中不被接受。

如果使用的变量比另一个变量的值少,则将使用最后一个值。

akin! {
    let &v1 = [c];
    let &v2 = [a, b];
    println!("*v1*v2");
}

展开为:

println!("ca");
println!("cb");

变量中的所有代码必须用括号括起来 {...}

akin! {
    let &var = [-1, 1];
    let &code = [
        {
            println!("true");
        },
        {
            println!("false");
        }
    ];
    
    if *var < 0 {
        *code
    }
}

将展开为:

if -1 < 0 {
    println!("true");
}
if 1 < 0 {
    println!("false")
}

请查看存储库中的 tests/ 文件夹以获取更多示例。

NONE

NONE 是你告诉 akin 简单跳过该值并写入内容的途径。
当你想在重复的元素中包含不需要在其他元素中的元素时很有用。


akin! {
    let &num = [1, 2, 3];
    let &code = [
        NONE,
        {
            .pow(2)
        }
    ];
    
    println!("*num^2 = {}", *num~u32*code);
    // *num~u32 is necessary to ensure the type is written correctly (it would be "1 u32" otherwise)
}

联合修饰符

默认情况下,akin 在所有标识符之间放置一个空格。

let name = 5; // 'name' is an identifier
    ^^^^

有时,这并不理想,例如,在尝试在函数名之间进行插值时。

let &name = [1];
fn _*name()...

// Will get wrongly expanded because '_' is an identifier
fn _ 1()

为了避免这种情况,请使用连接修饰符 ~,使下一个标识符不被分隔。

let &name = [1];
fn _~*name()... // *name is affected by the modifier

// Will get correctly expanded to
fn _1()

在字符串字面量 "..." 中,没有必要使用修饰符,因为 Rust 不将其视为标识符。

这是对 proc-macro 解析的限制,所以我怀疑它很快就会得到修复。

零依赖?真的吗?

是的,这个crate没有使用 synquote,因为解析语法很简单,并且两者都增加了很多开销。
因此,akin 不太可能像大多数 proc-macros 那样影响编译时间,试着用一下,你自己看看!

没有运行时依赖项