Если у вас есть это в C:
#define X(A,B) A+B
int r = X(1,2) * 3;
Значение r
будет 7
, потому что препроцессор расширяет его до 1+2 * 3
, то есть 1+(2*3)
.
В Rust вы получите:
macro_rules! X { ($a:expr,$b:expr) => { $a+$b } }
let r = X!(1,2) * 3;
Это будет равно 9
, потому что компилятор будет интерпретировать расширение как (1+2)*3
.Это связано с тем, что компилятор знает, что результатом макроса считается полное автономное выражение.
При этом макрос C также может быть определен так:
#define X(A,B) ((A)+(B))
Это позволило бы избежать каких-либо неочевидных проблем с оценкой, в том числе самих аргументов, интерпретируемых по-разному из-за контекста.Однако, когда вы используете макрос, вы никогда не можете быть уверены, правильно ли макрос учел все возможные способы его использования, поэтому трудно сказать, что будет делать любое данное расширение макроса.
Используя узлы AST вместо текста, Rust гарантирует, что эта двусмысленность не произойдет.