如何匹配 Rust 宏中的表达式类型? [英] How do I match the type of an expression in a Rust macro?

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

问题描述

这只是伪代码:

macro_rules! attribute {
    $e: expr<f32> => { /* magical float stuff */ };
    $e: expr<i64> => { /* mystical int stuff */ };
};

我想要一个不同的扩展宏,具体取决于我传递给宏的类型.

I would like to have a differently expanded macro depending on the type that I passed to the macro.

这就是它在 C++ 中的工作方式

This is how it would work in C++

template <typename T>
struct Attribute{ void operator(T)() {} };

template <>
struct Attribute<float> {
    void operator(float)(float) { /* magical float stuff */ }
};

template <>
struct Attribute<long> {
    void operator()(long) { /* mystical int stuff */ }
}

推荐答案

Rust 宏无法做到这一点.宏在句法级别运行,而不是在语义级别运行.这意味着虽然编译器知道它有一个表达式(语法),但它不知道在宏展开时表达式的值(语义)的类型是什么.

Rust macros aren't able to do that. Macros operate at the syntactic level, not at the semantic level. That means that although the compiler knows it has an expression (syntax), it doesn't know what the type of the expression's value (semantic) is at the moment the macro is expanded.

一种解决方法是将预期类型传递给宏:

A workaround would be to pass the expected type to the macro:

macro_rules! attribute {
    ($e:expr, f32) => { /* magical float stuff */ };
    ($e:expr, i64) => { /* mystical int stuff */ };
}

fn main() {
    attribute!(2 + 2, i64);
}

或者,更简单地说,定义多个宏.

Or, more simply, define multiple macros.

如果您想根据表达式的类型进行静态(编译时)分派,您可以使用特征.使用必要的方法定义特征,然后为您需要的类型实现特征.如果 impl 块与 trait 定义在同一个 crate 中,你可以为任何类型(包括来自其他库的原语和类型)实现一个 trait.

If you want to do static (compile-time) dispatch based on the type of an expression, you can use traits. Define a trait with the necessary methods, then implement the trait for the types you need. You can implement a trait for any type (including primitives and types from other libraries) if the impl block is in the same crate as the trait definition.

trait Attribute {
    fn process(&self);
}

impl Attribute for f32 {
    fn process(&self) { /* TODO */ }
}

impl Attribute for i64 {
    fn process(&self) { /* TODO */ }
}

macro_rules! attribute {
    ($e:expr) => { Attribute::process(&$e) };
}

fn main() {
    attribute!(2 + 2);
}

注意:您也可以在宏的主体中编写 $e.process(),但这样宏可能会调用不相关的 process 方法.

Note: You could also write $e.process() in the macro's body, but then the macro might call an unrelated process method.

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

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