Макросы
Функциональность и синтаксис Rust могут быть расширены с помощью пользовательских определений,
называемых макросами. Им даются имена, и они вызываются через единообразный
синтаксис: some_extension!(...).
Существует два способа определения новых макросов:
- Макросы по примеру определяют новый синтаксис на более высоком, декларативном уровне.
- Процедурные макросы определяют функциональноподобные макросы, пользовательские наследования (derives) и пользовательские атрибуты с помощью функций, работающих с входными токенами.
Вызов макроса
Syntax
MacroInvocation →
SimplePath ! DelimTokenTree
DelimTokenTree →
( TokenTree* )
| [ TokenTree* ]
| { TokenTree* }
TokenTree →
Tokenкроме разделителей | DelimTokenTree
MacroInvocationSemi →
SimplePath ! ( TokenTree* ) ;
| SimplePath ! [ TokenTree* ] ;
| SimplePath ! { TokenTree* }
Вызов макроса раскрывает макрос во время компиляции и заменяет вызов результатом работы макроса. Макросы могут быть вызваны в следующих ситуациях:
- Элементы, включая ассоциированные элементы
- Транскрайберы
macro_rules
При использовании в качестве элемента или инструкции используется форма MacroInvocationSemi,
где точка с запятой требуется в конце, если не используются фигурные скобки.
Квалификаторы видимости никогда не разрешаются перед вызовом макроса или
определением macro_rules.
#![allow(unused)] fn main() { // Используется как выражение. let x = vec![1,2,3]; // Используется как инструкция. println!("Hello!"); // Используется в шаблоне. macro_rules! pat { ($i:ident) => (Some($i)) } if let pat!(x) = Some(1) { assert_eq!(x, 1); } // Используется в типе. macro_rules! Tuple { { $A:ty, $B:ty } => { ($A, $B) }; } type N2 = Tuple!(i32, i32); // Используется как элемент. use std::cell::RefCell; thread_local!(static FOO: RefCell<u32> = RefCell::new(1)); // Используется как ассоциированный элемент. macro_rules! const_maker { ($t:ty, $v:tt) => { const CONST: $t = $v; }; } trait T { const_maker!{i32, 7} } // Вызовы макросов внутри макросов. macro_rules! example { () => { println!("Макрос внутри макроса!") }; } // Сначала раскрывается внешний макрос `example`, затем внутренний макрос `println`. example!(); }