如何评估 Rust 宏系统中的表达式? [英] How do I evaluate expressions in Rust's macro system?

查看:49
本文介绍了如何评估 Rust 宏系统中的表达式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to learn the Rust macro system by writing a simple macro that generates a struct based on some unsigned integer type (u8, u16, u32, u64). I want something like this:

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

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

To be more specific, I'm looking for some way to store certain information in an unsigned integer type with various offsets. One use case is to read some bytes and construct some kind of "message":

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

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

The higher part of the message contains some data/information, the lower part a versioning field. (This is just a toy example).

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

This is my effort so far, but the inner repeating expansion does not compile:

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

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

One solution could be to store the relevant bytes in a struct, implementing it directly (or with a trait) to get the appropriate fields, but this would involve too much bit-shifting logic (no problem with that, but there must be a more convenient way).

我知道 bitflags位域.它们都不符合我的用例.

I am aware of bitflags and bitfield. Neither of them matches my use case.

推荐答案

声明性宏 (macro_rules)

您不能对声明性宏中的表达式求值.声明性宏仅创建、删除或移动输入代码的抽象语法树 (AST) 的一部分.在宏扩展期间不进行求值(即使名称扩展"也是一个提示).

Declarative macros (macro_rules)

You cannot evaluate expressions in a declarative macro. Declarative macros only create, remove, or move around parts of the input code's abstract syntax tree (AST). No evaluation occurs during macro expansion (even the name "expansion" is a hint).

您能做的最好的事情是创建可以在编译时评估的代码,在宏扩展之后.在编译时有效的代码子集是有限的,但将来会增加.

The best you can do is create code that can be evaluated at compile time, after the macros have been expanded. The subset of code that is valid at compile time is limited, but it will grow in the future.

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

Procedural macros are more complicated but more powerful. These are implemented as arbitrary Rust code and they can parse arbitrary Rust code, outputting more arbitrary Rust code.

然而,无法重用评估 Rust 代码的常规方法.您将不得不接受文字值并自己进行所有计算.

However, there's no ability to reuse the normal ways of evaluating Rust code. You will have to accept literal values and do all the computation yourself.

不清楚您希望宏的结果是什么.请记住,宏没有能力组成"新的 Rust 概念,它们只允许您用更少的字符表达现有的重复概念.

It's unclear what you want the result of the macro to be. Remember that macros don't have the ability to "make up" new Rust concepts, they only allow you to express existing repeated concepts with fewer characters.

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

Because of this, I always recommend that people write out the first two repeated cases fully. This forces you to write the full valid Rust code and identify the differences between them. You can then extract the commonality using any normal Rust technique.

另见:

这篇关于如何评估 Rust 宏系统中的表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆