如何评估 Rust 宏系统中的表达式?

Posted

技术标签:

【中文标题】如何评估 Rust 宏系统中的表达式?【英文标题】:How do I evaluate expressions in Rust's macro system? 【发布时间】:2018-09-09 15:21:26 【问题描述】:

我正在尝试通过编写一个简单的宏来学习 Rust 宏系统,该宏基于一些无符号整数类型(u8u16u32u64)生成一个结构。我想要这样的东西:

bitmessage! 
    struct Header(u16);
    version: 8, 5; // the first number is the length, second is value
    data: 8, 5;

更具体地说,我正在寻找某种方法将某些信息存储在具有各种偏移量的无符号整数类型中。一个用例是读取一些字节并构造某种“消息”:

[ 15 14 13 12 11 10 09 08 | 07 06 05 04 03 02 01 01 ]

消息的上半部分包含一些数据/信息,下半部分是版本控制字段。 (这只是一个玩具示例)。

这是我到目前为止的努力,但内部重复扩展无法编译:

macro_rules! bitmessage 
(struct $name:ident($n:ty); 
    $($field_name:ident: $length:expr, $value:expr;)*)  => 
         struct $name ($n);
         $($name.1 = $name.1 | $value << $length)*
    ;

一种解决方案可能是将相关字节存储在结构中,直接(或使用特征)实现它以获取适当的字段,但这会涉及太多的位移逻辑(这没有问题,但必须是一种更方便的方式)。

我知道bitflags 和bitfield。它们都不符合我的用例。

【问题讨论】:

【参考方案1】:

声明性宏 (macro_rules)

您不能评估声明性宏中的表达式。声明性宏仅创建、删除或移动输入代码的抽象语法树 (AST) 的一部分。宏扩展期间不进行评估(甚至名称“扩展”也是一个提示)。

您可以做的最好的事情是创建可以在宏展开后在编译时进行评估的代码。在编译时有效的代码子集是有限的,但它会在未来增长。

过程宏

过程宏更复杂但更强大。这些实现为任意 Rust 代码,它们可以解析任意 Rust 代码,输出更多任意 Rust 代码。

但是,无法重用评估 Rust 代码的常规方法。您必须接受文字值并自己完成所有计算。

你的具体例子

不清楚您希望宏的结果是什么。请记住,宏不能“组成”新的 Rust 概念,它们只能让您用更少的字符来表达现有的重复概念。

因此,我总是建议人们完整地写出前两个重复的案例。这迫使您编写完整的有效 Rust 代码并识别它们之间的差异。然后,您可以使用任何普通的 Rust 技术提取共性。

另见:

The Little Book of Rust Macros Is there a way to count with macros?

【讨论】:

我明白了。我越想越得出结论,使用宏反序列化二进制消息是错误的方法。感谢您解决这个问题。

以上是关于如何评估 Rust 宏系统中的表达式?的主要内容,如果未能解决你的问题,请参考以下文章

在编译时计算一组常量表达式的最大值

在 C++ 中以 1 个表达式实例化对象的可自定义方式

如何评估作为列值的表达式?

如何在宏中匹配 Rust 的“if”表达式?

如何在使用Rust的正则表达式包时逃脱转义的正则表达式字符?

Rust语言教程 - if let表达式与枚举进阶