是否可以使用Rust宏在程序上声明变量? [英] Is it possible to declare variables procedurally using Rust macros?

查看:165
本文介绍了是否可以使用Rust宏在程序上声明变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,这个问题有两个部分:

Basically, there are two parts to this question:

  1. 您可以将未知的标识符传递给 Rust 中的宏吗?

您可以在Rust宏中组合字符串以生成新的变量名称吗?

Can you combine strings to generate new variable names in a Rust macro?

例如,类似:

macro_rules! expand(
  ($x:ident) => (
    let mut x_$x = 0;
  )
)

调用expand!(hi)显然失败,因为hi是一个未知的标识符;但是你能以某种方式做到这一点吗?

Calling expand!(hi) obvious fails because hi is an unknown identifier; but can you somehow do this?

即.在C中相当于:

#include <stdio.h>
#define FN(Name, base) \
  int x1_##Name = 0 + base; \
  int x2_##Name = 2 + base; \
  int x3_##Name = 4 + base; \
  int x4_##Name = 8 + base; \
  int x5_##Name = 16 + base;

int main() {
  FN(hello, 10)
  printf("%d %d %d %d %d\n", x1_hello, x2_hello, x3_hello, x4_hello, x5_hello);
  return 0;
}

你为什么这么说,这是一个多么糟糕的主意.您为什么要这么做?

Why you say, what a terrible idea. Why would you ever want to do that?

很高兴你问!

考虑此防锈块:

{
   let marker = 0;
   let borrowed = borrow_with_block_lifetime(data, &marker); 
   unsafe {
      perform_ffi_call(borrowed);
   }
}

您现在有了一个借用的值,该值具有未使用结构寿命的显式有限寿命(标记),但是我们可以保证在ffi调用的整个范围内都存在该值.同时,在不安全的块中不安全地取消引用*的情况下,我们不会遇到晦涩的错误,因此即使在安全的内部将设为错误,编译器也不会将其视为错误.阻止.

You now have a borrowed value with an explicitly bounded lifetime (marker) that isn't using a structure lifetime, but that we can guarantee exists for the entire scope of the ffi call; at the same time we don't run into obscure errors where a * is de-referenced unsafely inside an unsafe block and so the compiler doesn't catch it as an error, despite the error being made inside a safe block.

(另请参见为此目的使用可以声明临时变量的宏将大大减轻我与编译器争用的麻烦.这就是为什么我要这样做.

The use a macro that can declare temporary variables for this purpose would considerably ease the troubles I have fighting with the compiler. That's why I want to do this.

推荐答案

是的,您可以将任意标识符传递到宏中,是的,您可以使用

Yes, you can pass arbitrary identifier into a macro and yes, you can concatenate identifiers into a new identifier using concat_idents!() macro:

#![feature(concat_idents)]

macro_rules! test {
    ($x:ident) => ({
        let z = concat_idents!(hello_, $x);
        z();
    })
}

fn hello_world() {  }

fn main() {
    test!(world);
}

但是,据我所知,由于concat_idents!()本身是一个宏,因此您不能在任何地方使用此级联标识符 ,只能在某些地方使用纯标识符,例如上面的示例,我认为这是一个巨大的缺点.就在昨天,我试图编写一个宏,该宏可以删除代码中的许多样板,但最终我无法做到这一点,因为宏不支持串联标识符的任意放置.

However, as far as I know, because concat_idents!() itself is a macro, you can't use this concatenated identifier everywhere you could use plain identifier, only in certain places like in example above, and this, in my opinion, is a HUGE drawback. Just yesterday I tried to write a macro which could remove a lot of boilerplate in my code, but eventually I was not able to do it because macros do not support arbitrary placement of concatenated identifiers.

顺便说一句,如果我正确地理解了您的想法,那么您实际上不需要串联标识符来获得唯一的名称.与C相反,Rust宏是卫生.这意味着在宏中引入的所有局部变量名称都不会泄漏到调用此宏的作用域中.例如,您可以假定此代码将起作用:

BTW, if I understand your idea correctly, you don't really need concatenating identifiers to obtain unique names. Rust macros, contrary to the C ones, are hygienic. This means that all names of local variables introduced inside a macro won't leak to the scope where this macro is called. For example, you could assume that this code would work:

macro_rules! test {
    ($body:expr) => ({ let x = 10; $body })
}

fn main() {
    let y = test!(x + 10);
    println!("{}", y);
}

也就是说,我们创建一个变量x,并在其声明后放置一个表达式.然后自然会想到test!(x + 10)中的x引用由宏声明的变量,并且一切都应该没问题,但实际上此代码无法编译:

That is, we create a variable x and put an expression after its declaration. It is then natural to think that x in test!(x + 10) refers to that variable declared by the macro, and everything should be fine, but in fact this code won't compile:

main3.rs:8:19: 8:20 error: unresolved name `x`.
main3.rs:8     let y = test!(x + 10);
                             ^
main3.rs:3:1: 5:2 note: in expansion of test!
main3.rs:8:13: 8:27 note: expansion site
error: aborting due to previous error

因此,如果您所需要的只是本地人的唯一性,那么您可以放心地不做任何事情,也可以使用任何想要的名称,它们将自动成为唯一的.这是宏教程中的解释,尽管我发现这个例子有点令人困惑.

So if all you need is uniqueness of locals, then you can safely do nothing and use any names you want, they will be unique automatically. This is explained in macro tutorial, though I find the example there somewhat confusing.

这篇关于是否可以使用Rust宏在程序上声明变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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