Macros¶
Level: 101 → 201 · for newcomers
One line: The ! means the call is expanded into source code before compilation, which is how println! can check your format string at compile time and how vec![] can take a list of anything — neither is possible for an ordinary function.
Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The bullets below are the questions the finished page has to answer.
What it has to cover¶
- What the
!actually tells you at a call site, and what it does not (it is not "unsafe", not "special", not a negation) - The handful worth knowing on day one:
println!/format!/vec!/assert!/assert_eq!/panic!/dbg!/todo! - Why a macro can do things a function cannot: a variable number of arguments, arguments of different types, and inspecting the source text — which is how
dbg!prints the expression you wrote - Why the format string must be a literal, and the error you get when you pass a
String - The two kinds — declarative (
macro_rules!) and procedural (#[derive(Debug)]is one) — named, with writing one deferred cargo expandas the way to stop guessing what a macro became
The trap it exists for¶
A macro is not a function, so the usual intuitions about evaluation do not hold: an argument may be evaluated twice, never, or in a different order. This is why assert! can print the expression that failed, and why a macro that looks like it takes a value may actually be taking a place.
See also¶
- The braces take a name —
println!'s format string in detail, and the three ways{}refuses - What
dbg!does — the macro that reads its own source text, and the five things it does thatprintln!does not DebugandDisplay— the traits the printing macros call, and why only one can be derivedunwrapis a TODO —todo!andunimplemented!as the honest placeholders- Comprehensive Rust: Macros ↗
Po polsku¶
Wykrzyknik po nazwie nie oznacza ani negacji, ani niczego niebezpiecznego — mówi tylko tyle, że wywołanie zostanie rozwinięte w kod źródłowy jeszcze przed kompilacją. Warto od razu odciąć skojarzenie z C: makro w Ruscie to nie #define operujące na tekście, lecz przekształcenie drzewa składni, dzięki czemu println! sprawdza łańcuch formatujący już podczas kompilacji, a vec![] przyjmuje listę czegokolwiek — zwykła funkcja nie potrafi ani jednego, ani drugiego. Trzy rzeczy są zarezerwowane właśnie dla makr: zmienna liczba argumentów, argumenty różnych typów i zaglądanie do tekstu źródłowego — to ostatnie sprawia, że dbg! wypisuje wyrażenie dokładnie w takiej postaci, w jakiej je napisaliśmy. Pułapka jest jednak taka, że makro nie jest funkcją i intuicje o obliczaniu argumentów przestają obowiązywać (argument może zostać policzony dwa razy, ani razu albo w innej kolejności), a łańcuch formatujący musi być literałem — podanie zmiennej typu String kończy się błędem; kiedy nie wiadomo, w co dane makro się rozwinęło, odpowiedzi udziela cargo expand.
Szukaj po polsku: makra w Ruscie · rozwinięcie makra · macro_rules! · rust macro vs function · cargo expand