Is it possible to declare variables procedurally using Rust macros? -
basically, there 2 parts question:
can pass unknown identifier macro in rust?
can combine strings generate new variable names in rust macro?
for example, like:
macro_rules! expand( ($x:ident) => ( let mut x_$x = 0; ) )
calling expand!(hi) obvious fails because hi unknown identifier; can somehow this?
ie. equivalent in c of like:
#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 say, terrible idea. why ever want that?
i'm glad asked!
consider rust block:
{ let marker = 0; let borrowed = borrow_with_block_lifetime(data, &marker); unsafe { perform_ffi_call(borrowed); } }
you have borrowed value explicitly bounded lifetime (marker) isn't using structure lifetime, can guarantee exists entire scope of ffi call; @ same time don't run obscure errors *
de-referenced unsafely inside unsafe block , compiler doesn't catch error, despite error being made inside safe block.
(see why pointers pointing same place to_c_str() in rust?)
the use macro can declare temporary variables purpose considerably ease troubles have fighting compiler. that's why want this.
yes, can pass arbitrary identifier macro , yes, can concatenate identifiers new identifier using concat_idents!()
macro:
macro_rules! test( ($x:ident) => ({ let z = concat_idents!(hello_, $x); z(); }) ) fn hello_world() { ... } fn main() { test!(world); }
however, far know, because concat_idents!()
macro, can't use concatenated identifier everywhere use plain identifier, in places in example above, , this, in opinion, huge drawback. yesterday tried write macro remove lot of boilerplate in code, not able because macros not support arbitrary placement of concatenated identifiers.
btw, if understand idea correctly, don't need concatenating identifiers obtain unique names. rust macros, contrary c ones, hygienic. means names of local variables introduced inside macro won't leak scope macro called. example, assume code work:
#![feature(macro_rules)] macro_rules! test( ($body:expr) => ({ let x = 10; $body }) ) fn main() { let y = test!(x + 10); println!("{}", y); }
that is, create variable x
, put expression after declaration. natural think x
in test!(x + 10)
refers variable declared macro, , should fine, in fact 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 previous error
so if need uniqueness of locals, can safely nothing , use names want, unique automatically. explained in macro tutorial, though find example there confusing.
Comments
Post a Comment