简体   繁体   English

我可以在宏输入中指定运算符或其他语法文字吗?

[英]Can I specify an operator or other syntactic literal within a macro input?

First, I know this is not a good use of macros but I'm learning what I can do.首先,我知道这不是很好地使用宏,但我正在学习我能做什么。

I have a struct Rational :我有一个结构Rational

pub struct Rational{
    pub n: i128,
    pub d : i128
}

I have a macro that builds these:我有一个构建这些的宏:

macro_rules! rat{
    ($n : expr,  $d : expr) => {
        Rational{n : $n,d:  $d}
    }
}

The syntax for calling that macro looks like: rat,(1, 3) .调用该宏的语法如下所示: rat,(1, 3) I would like it to visually show a fractional format, so you would call it like rat!(1 / 3) instead, and the macro would parse that expression to yield the same result.我希望它直观地显示小数格式,因此您可以像rat!(1 / 3)那样称呼它,宏将解析该表达式以产生相同的结果。 (Note that if it first evaluates 1/3 , even as a float type, it will not exactly correspond as 1/3 does not correspond exactly to any float.) (请注意,如果它首先评估1/3 ,即使是浮点类型,它也不会完全对应,因为1/3不完全对应于任何浮点数。)

I'm hoping there's some syntax like:我希望有一些语法,例如:

macro_rules! rat{
    ($n : expr `/` $d : expr) => {
        Rational{n : $n,d:  $d}
    }
}

where I can specify syntax to be used in the call.我可以在其中指定要在调用中使用的语法。 (That attempt does not compile, of course.) (当然,这种尝试不会编译。)

Again, obviously this is silly and an X/Y problem and all that.同样,显然这是一个愚蠢的 X/Y 问题等等。 For context, I'm considering building an equation wrangling system, and at some point I'd like to be able to parse things from a math-y syntax, which might actually justify the use of macros.对于上下文,我正在考虑构建一个方程式争论系统,并且在某些时候我希望能够从 math-y 语法中解析事物,这实际上可能证明使用宏是合理的。 This is just a baby step.这只是一小步。

Does such a thing exist using declarative macros?使用声明性宏是否存在这样的事情? If not, is it possible with procedural macros?如果没有,是否可以使用程序宏? Finally, I know that in Scala macros there would be no way to make that work for literal values, because the expression 1/3 would be resolved so early in the compilation process the AST would be gone by the time even macros are called.最后,我知道在 Scala 宏中,没有办法使它对文字值起作用,因为表达式1/3会在编译过程的早期被解析,甚至在调用宏时 AST 也会消失。 Is that also the case in Rust? Rust也是这样吗?

Yes, you can use the / token directly in the rule:是的,您可以直接在规则中使用/令牌:

#[derive(Debug)]
struct Rational{
    n: i128,
    d: i128
}

macro_rules! rat {
    ($n:literal / $d:literal) => {
        Rational { n: $n, d: $d }
    };
}

fn main() {
    println!("rat!(1 / 3) = {:?}", rat!(1 / 3));
}
rat!(1 / 3) = Rational { n: 1, d: 3 }

However, notice I have changed the arguments from expr to literal .但是,请注意我已将 arguments 从expr更改为literal Your question seems to imply this is fine for your use-case, but I bring it up because at least the first parameter $n cannot be an expr .你的问题似乎暗示这对你的用例来说很好,但我提出它是因为至少第一个参数$n不能是expr It would cause a parsing ambiguity because / is a valid continuation of an expression and Rust simply doesn't allow / as a separator after a expr .这会导致解析歧义,因为/是表达式的有效延续,而 Rust 根本不允许/作为expr之后的分隔符。 And this goes for all operators;这适用于所有运营商; from the follow-set ambiguity restrictions , only => , , , or ;follow-set ambiguity restrictions , only => , , , or ; may follow an expr .可以跟随一个expr

If you do want to allow any expr , a common trick is to require parenthesis:如果你确实想允许任何expr ,一个常见的技巧是需要括号:

macro_rules! rat {
    ($n:literal / $d:expr) => {
        Rational { n: $n, d: $d }
    };
    (($n:expr) / $d:expr) => {
        Rational { n: $n, d: $d }
    };
}

fn main() {
    println!("rat!(1 / 3) = {:?}", rat!(1 / 3));
    println!("rat!((1 + 2) / 3) = {:?}", rat!((1 + 2) / 3));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM