The trustc version is 1.65.0.
The following code has an error and cannot be compiled.
Code of interest:
fnmain(){
test_macro!{
12, x, y
}
x+y+temp;
}
# [macro_export]
US>macro_rules!test_macro{
($e:expr, $x:ident, $y:ident) = > {
let$x=$e;
let temp = $e;
let$y=$e;
};
}
error messages:
error [E0425]:cannot find value `temp` in this scope
-->src/main.rs:6:13
|
6 | x + y + temp;
| ^^^^ not found in this scope
For more information about this error, try `rustc--explain E0425`.
error: could not compile `playground` due to previous error
By the way, if you enter this code and run cargo-expand
, you will get the code from which you expanded the macro as follows:
#![feature(prelude_import)]
# [prelude_import]
use std::prelude::rust_2021::*;
# [macro_use]
external crate std;
US>fnmain(){
let x = 12;
let temp = 12;
letty = 12;
x+y+temp;
}
As far as reading this, temp
is visible from the x+y+temp
section (similar to x
, y
.(And this is what I expected.)
Please tell me why temp
is not visible in the original code.
Rust's declarative macro is healthy (hygienic) for variable names.
A healthy macro (Hygienic macro) is a macro that is guaranteed to avoid the problem of incorrectly capturing identifiers.
—— Healthy Macro-Wikipedia
The variable name introduced in the macro does not conflict with the variable name of the macro caller. (In the sense of Lisp macro, sanitation)
—— How is Rust Macro sanitizing (1/2) Identifier sanitizing
In the example question, the let temp=$e;
of the macro expands to let temp=12;
, which is different from the temp
outside the macro because temp
is the identifier written in the macro.You can think of it as automatically changing the name, but cargo-expand
doesn't seem to visualize it.
This distinction is similar to the scope created by the block.However, the nested state is different from the visible block, so it seems that the macro-made part is explained that it is painted in a different color.
To understand a healthy macro, each time a macro is deployed, it can be considered that the part developed from the macro is painted in a different color.
Different "color" variables are treated as if they were different names.
—— Programming Rust 2nd Edition 21.4.4 Scope and Healthy Macros
The Little Book of Rust Macros also explains by painting different background colors.
Therefore, if you import the identifier from outside the macro (the user side), the example question will not fail.
fnmain(){
test_macro!{
12, x, y, temp
}
println!("{}, x+y+temp);
}
# [macro_export]
US>macro_rules!test_macro{
($e:expr, $x:ident, $y:ident, $temp_var:ident) = > {
let$x=$e;
let$temp_var=$e;
let$y=$e;
};
}
Alternatively, I think procedural macros are different, so you may be able to handle identifiers more freely.
© 2024 OneMinuteCode. All rights reserved.