我正在尝试通过编写一个简单的宏来学习 Rust 宏系统,该宏生成基于某些无符号整数类型(u8, u16, u32, u64)的结构。我想要这样的东西:
bitmessage! {
struct Header(u16);
version: 8, 5; // the first number is the length, second is value
data: 8, 5;
}
Run Code Online (Sandbox Code Playgroud)
更具体地说,我正在寻找某种方法来将某些信息存储在具有各种偏移量的无符号整数类型中。一个用例是读取一些字节并构造某种“消息”:
bitmessage! {
struct Header(u16);
version: 8, 5; // the first number is the length, second is value
data: 8, 5;
}
Run Code Online (Sandbox Code Playgroud)
消息的较高部分包含一些数据/信息,较低部分包含版本控制字段。(这只是一个玩具示例)。
这是我到目前为止的努力,但内部重复扩展无法编译:
macro_rules! bitmessage {
(struct $name:ident($n:ty);
$($field_name:ident: $length:expr, $value:expr;)*) => {
struct $name ($n);
$($name.1 = $name.1 | $value << $length)*
};
}
Run Code Online (Sandbox Code Playgroud)
一种解决方案可能是将相关字节存储在结构中,直接实现它(或使用特征)来获取适当的字段,但这会涉及太多的位移逻辑(这没有问题,但必须有更多)方便的方式)。
macro_rules)您不能计算声明性宏中的表达式。声明性宏仅创建、删除或移动输入代码的抽象语法树 (AST) 的部分内容。宏展开期间不会进行求值(即使名称“展开”也是一个暗示)。
您能做的最好的事情就是创建可以在宏展开后在编译时评估的代码。编译时有效的代码子集是有限的,但将来会增长。
过程宏更复杂但更强大。它们被实现为任意 Rust 代码,并且它们可以解析任意 Rust 代码,输出更多任意 Rust 代码。
但是,无法重用评估 Rust 代码的正常方法。您必须接受文字值并自己完成所有计算。
目前尚不清楚您希望宏的结果是什么。请记住,宏没有能力“组成”新的 Rust 概念,它们只允许您用更少的字符表达现有的重复概念。
正因为如此,我总是建议人们完整地写出前两个重复的案例。这迫使您编写完整有效的 Rust 代码并识别它们之间的差异。然后,您可以使用任何普通的 Rust 技术来提取共性。
也可以看看: