Я читаю книгу о Rust и начинаю играть с Rust macros. Здесь описываются все метапарабельные типы, и есть примеры, кроме последнего - tt
. Согласно книге, это "единственное дерево-маркер". Мне любопытно, что это такое и для чего он используется? Можете ли вы привести пример?
Что означает метастабильный тип tt в макросах Rust?
Ответ 1
Это понятие введено, чтобы гарантировать, что все, что находится в вызове макроса, правильно соответствует парам ()
, []
и {}
. tt
сопоставляет любой токен или любую пару скобок/скобок/скобок с их содержанием.
Например, для следующей программы:
fn main() {
println!("Hello world!");
}
Токен-деревья будут:
fn
main
()
- ∅
{ println!("Hello world!"); }
println
!
("Hello world!")
"Hello world!"
;
Каждый из них образует дерево, в котором простые токены (fn
, main
и т.д.) Являются листьями, а все, что окружено ()
, []
или {}
, имеет поддерево. Обратите внимание, что (
не отображается отдельно в дереве токенов: невозможно сопоставить (
без сопоставления с соответствующим )
.
Например:
macro_rules! {
(fn $name:ident $params:tt $body:tt) => { /* … */ }
}
будет соответствовать вышеуказанной функции с $name → main
, $params → ()
, $body → { println!("Hello world!"); }
.
Дерево токенов - это наименее требовательный тип метавариабельной переменной: он соответствует чему угодно. Он часто используется в макросах, в которых есть "не очень важно", особенно в макросах, в которых есть "голова" и "хвост". Например, макросы println!
имеют ветвь, совпадающую с ($fmt:expr, $($arg:tt)*)
, где $fmt
- строка формата, а $($arg:tt)*
означает "все остальное" и просто пересылается в format_args!
. Это означает, что println!
не нужно знать фактический формат и выполнять сложное сопоставление с ним.