mirror of
https://github.com/Dhghomon/easy_rust
synced 2024-11-15 18:13:23 +00:00
554 lines
34 KiB
HTML
554 lines
34 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en" class="sidebar-visible no-js light">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title> Writing macros - Easy Rust</title>
|
|
|
|
|
|
|
|
|
|
<!-- Custom HTML head -->
|
|
|
|
|
|
|
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
|
<meta name="description" content="">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="theme-color" content="#ffffff" />
|
|
|
|
|
|
<link rel="icon" href="favicon.svg">
|
|
|
|
|
|
<link rel="shortcut icon" href="favicon.png">
|
|
|
|
<link rel="stylesheet" href="css/variables.css">
|
|
<link rel="stylesheet" href="css/general.css">
|
|
<link rel="stylesheet" href="css/chrome.css">
|
|
|
|
<link rel="stylesheet" href="css/print.css" media="print">
|
|
|
|
|
|
<!-- Fonts -->
|
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
|
|
|
<link rel="stylesheet" href="fonts/fonts.css">
|
|
|
|
|
|
<!-- Highlight.js Stylesheets -->
|
|
<link rel="stylesheet" href="highlight.css">
|
|
<link rel="stylesheet" href="tomorrow-night.css">
|
|
<link rel="stylesheet" href="ayu-highlight.css">
|
|
|
|
<!-- Custom theme stylesheets -->
|
|
|
|
|
|
|
|
</head>
|
|
<body>
|
|
<!-- Provide site root to javascript -->
|
|
<script type="text/javascript">
|
|
var path_to_root = "";
|
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
|
</script>
|
|
|
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
<script type="text/javascript">
|
|
try {
|
|
var theme = localStorage.getItem('mdbook-theme');
|
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
|
|
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
}
|
|
|
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
}
|
|
} catch (e) { }
|
|
</script>
|
|
|
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
<script type="text/javascript">
|
|
var theme;
|
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
var html = document.querySelector('html');
|
|
html.classList.remove('no-js')
|
|
html.classList.remove('light')
|
|
html.classList.add(theme);
|
|
html.classList.add('js');
|
|
</script>
|
|
|
|
<!-- Hide / unhide sidebar before it is displayed -->
|
|
<script type="text/javascript">
|
|
var html = document.querySelector('html');
|
|
var sidebar = 'hidden';
|
|
if (document.body.clientWidth >= 1080) {
|
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
sidebar = sidebar || 'visible';
|
|
}
|
|
html.classList.remove('sidebar-visible');
|
|
html.classList.add("sidebar-" + sidebar);
|
|
</script>
|
|
|
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
<div class="sidebar-scrollbox">
|
|
<ol class="chapter"><li class="chapter-item expanded "><a href="Chapter_0.html"><strong aria-hidden="true">1.</strong> Update</a></li><li class="chapter-item expanded "><a href="Chapter_1.html"><strong aria-hidden="true">2.</strong> Introduction</a></li><li class="chapter-item expanded "><a href="Chapter_2.html"><strong aria-hidden="true">3.</strong> Who am I?</a></li><li class="chapter-item expanded "><a href="Chapter_3.html"><strong aria-hidden="true">4.</strong> Writing Rust in Easy English</a></li><li class="chapter-item expanded "><a href="Chapter_4.html"><strong aria-hidden="true">5.</strong> Rust Playground</a></li><li class="chapter-item expanded "><a href="Chapter_5.html"><strong aria-hidden="true">6.</strong> 🚧 and ⚠️</a></li><li class="chapter-item expanded "><a href="Chapter_6.html"><strong aria-hidden="true">7.</strong> Comments</a></li><li class="chapter-item expanded "><a href="Chapter_7.html"><strong aria-hidden="true">8.</strong> Types</a></li><li class="chapter-item expanded "><a href="Chapter_8.html"><strong aria-hidden="true">9.</strong> Type inference</a></li><li class="chapter-item expanded "><a href="Chapter_9.html"><strong aria-hidden="true">10.</strong> Printing 'hello, world!'</a></li><li class="chapter-item expanded "><a href="Chapter_10.html"><strong aria-hidden="true">11.</strong> Display and debug</a></li><li class="chapter-item expanded "><a href="Chapter_11.html"><strong aria-hidden="true">12.</strong> Mutability (changing)</a></li><li class="chapter-item expanded "><a href="Chapter_12.html"><strong aria-hidden="true">13.</strong> The stack, the heap, and pointers</a></li><li class="chapter-item expanded "><a href="Chapter_13.html"><strong aria-hidden="true">14.</strong> More about printing</a></li><li class="chapter-item expanded "><a href="Chapter_14.html"><strong aria-hidden="true">15.</strong> Strings</a></li><li class="chapter-item expanded "><a href="Chapter_15.html"><strong aria-hidden="true">16.</strong> const and static</a></li><li class="chapter-item expanded "><a href="Chapter_16.html"><strong aria-hidden="true">17.</strong> More on references</a></li><li class="chapter-item expanded "><a href="Chapter_17.html"><strong aria-hidden="true">18.</strong> Mutable references</a></li><li class="chapter-item expanded "><a href="Chapter_18.html"><strong aria-hidden="true">19.</strong> Giving references to functions</a></li><li class="chapter-item expanded "><a href="Chapter_19.html"><strong aria-hidden="true">20.</strong> Copy types</a></li><li class="chapter-item expanded "><a href="Chapter_20.html"><strong aria-hidden="true">21.</strong> Collection types</a></li><li class="chapter-item expanded "><a href="Chapter_21.html"><strong aria-hidden="true">22.</strong> Vectors</a></li><li class="chapter-item expanded "><a href="Chapter_22.html"><strong aria-hidden="true">23.</strong> Tuples</a></li><li class="chapter-item expanded "><a href="Chapter_23.html"><strong aria-hidden="true">24.</strong> Control flow</a></li><li class="chapter-item expanded "><a href="Chapter_24.html"><strong aria-hidden="true">25.</strong> Structs</a></li><li class="chapter-item expanded "><a href="Chapter_25.html"><strong aria-hidden="true">26.</strong> Enums</a></li><li class="chapter-item expanded "><a href="Chapter_26.html"><strong aria-hidden="true">27.</strong> Loops</a></li><li class="chapter-item expanded "><a href="Chapter_27.html"><strong aria-hidden="true">28.</strong> Implementing structs and enums</a></li><li class="chapter-item expanded "><a href="Chapter_28.html"><strong aria-hidden="true">29.</strong> Destructuring</a></li><li class="chapter-item expanded "><a href="Chapter_29.html"><strong aria-hidden="true">30.</strong> References and the dot operator</a></li><li class="chapter-item expanded "><a href="Chapter_30.html"><strong aria-hidden="true">31.</strong> Generics</a></li><li class="chapter-item expanded "><a href="Chapter_31.html"><strong aria-hidden="true">32.</strong> Option and Result</a></li><li class="chapter-item expanded "><a href="Chapter_32.html"><strong aria-hidden="true">33.</strong> Other collections</a></li><li class="chapter-item expanded "><a href="Chapter_33.html"><strong aria-hidden="true">34.</strong> The ? operator</a></li><li class="chapter-item expanded "><a href="Chapter_34.html"><strong aria-hidden="true">35.</strong> Traits</a></li><li class="chapter-item expanded "><a href="Chapter_35.html"><strong aria-hidden="true">36.</strong> Chaining methods</a></li><li class="chapter-item expanded "><a href="Chapter_36.html"><strong aria-hidden="true">37.</strong> Iterators</a></li><li class="chapter-item expanded "><a href="Chapter_37.html"><strong aria-hidden="true">38.</strong> Closures</a></li><li class="chapter-item expanded "><a href="Chapter_38.html"><strong aria-hidden="true">39.</strong> The dbg! macro and .inspect</a></li><li class="chapter-item expanded "><a href="Chapter_39.html"><strong aria-hidden="true">40.</strong> Types of &str</a></li><li class="chapter-item expanded "><a href="Chapter_40.html"><strong aria-hidden="true">41.</strong> Lifetimes</a></li><li class="chapter-item expanded "><a href="Chapter_41.html"><strong aria-hidden="true">42.</strong> Interior mutability</a></li><li class="chapter-item expanded "><a href="Chapter_42.html"><strong aria-hidden="true">43.</strong> RefCell</a></li><li class="chapter-item expanded "><a href="Chapter_43.html"><strong aria-hidden="true">44.</strong> Mutex</a></li><li class="chapter-item expanded "><a href="Chapter_44.html"><strong aria-hidden="true">45.</strong> RwLock</a></li><li class="chapter-item expanded "><a href="Chapter_45.html"><strong aria-hidden="true">46.</strong> Cow</a></li><li class="chapter-item expanded "><a href="Chapter_46.html"><strong aria-hidden="true">47.</strong> Type aliases</a></li><li class="chapter-item expanded "><a href="Chapter_47.html"><strong aria-hidden="true">48.</strong> The todo! macro</a></li><li class="chapter-item expanded "><a href="Chapter_48.html"><strong aria-hidden="true">49.</strong> Rc</a></li><li class="chapter-item expanded "><a href="Chapter_49.html"><strong aria-hidden="true">50.</strong> Multiple threads</a></li><li class="chapter-item expanded "><a href="Chapter_50.html"><strong aria-hidden="true">51.</strong> Closures in functions</a></li><li class="chapter-item expanded "><a href="Chapter_51.html"><strong aria-hidden="true">52.</strong> impl Trait</a></li><li class="chapter-item expanded "><a href="Chapter_52.html"><strong aria-hidden="true">53.</strong> Arc</a></li><li class="chapter-item expanded "><a href="Chapter_53.html"><strong aria-hidden="true">54.</strong> Channels</a></li><li class="chapter-item expanded "><a href="Chapter_54.html"><strong aria-hidden="true">55.</strong> Reading Rust documentation</a></li><li class="chapter-item expanded "><a href="Chapter_55.html"><strong aria-hidden="true">56.</strong> Attributes</a></li><li class="chapter-item expanded "><a href="Chapter_56.html"><strong aria-hidden="true">57.</strong> Box</a></li><li class="chapter-item expanded "><a href="Chapter_57.html"><strong aria-hidden="true">58.</strong> Box around traits</a></li><li class="chapter-item expanded "><a href="Chapter_58.html"><strong aria-hidden="true">59.</strong> Default and the builder pattern</a></li><li class="chapter-item expanded "><a href="Chapter_59.html"><strong aria-hidden="true">60.</strong> Deref and DerefMut</a></li><li class="chapter-item expanded "><a href="Chapter_60.html"><strong aria-hidden="true">61.</strong> Crates and modules</a></li><li class="chapter-item expanded "><a href="Chapter_61.html"><strong aria-hidden="true">62.</strong> Testing</a></li><li class="chapter-item expanded "><a href="Chapter_62.html"><strong aria-hidden="true">63.</strong> External crates</a></li><li class="chapter-item expanded "><a href="Chapter_63.html"><strong aria-hidden="true">64.</strong> A tour of the standard library</a></li><li class="chapter-item expanded "><a href="Chapter_64.html" class="active"><strong aria-hidden="true">65.</strong> Writing macros</a></li><li class="chapter-item expanded "><a href="Chapter_65.html"><strong aria-hidden="true">66.</strong> cargo</a></li><li class="chapter-item expanded "><a href="Chapter_66.html"><strong aria-hidden="true">67.</strong> Taking user input</a></li><li class="chapter-item expanded "><a href="Chapter_67.html"><strong aria-hidden="true">68.</strong> Using files</a></li><li class="chapter-item expanded "><a href="Chapter_68.html"><strong aria-hidden="true">69.</strong> cargo doc</a></li><li class="chapter-item expanded "><a href="Chapter_69.html"><strong aria-hidden="true">70.</strong> The end?</a></li></ol>
|
|
</div>
|
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
|
</nav>
|
|
|
|
<div id="page-wrapper" class="page-wrapper">
|
|
|
|
<div class="page">
|
|
|
|
<div id="menu-bar-hover-placeholder"></div>
|
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
|
<div class="left-buttons">
|
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
<i class="fa fa-bars"></i>
|
|
</button>
|
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
<i class="fa fa-paint-brush"></i>
|
|
</button>
|
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
</ul>
|
|
|
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<h1 class="menu-title">Easy Rust</h1>
|
|
|
|
<div class="right-buttons">
|
|
|
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
|
<i id="print-button" class="fa fa-print"></i>
|
|
</a>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div id="search-wrapper" class="hidden">
|
|
<form id="searchbar-outer" class="searchbar-outer">
|
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
</form>
|
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
<div id="searchresults-header" class="searchresults-header"></div>
|
|
<ul id="searchresults">
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
<script type="text/javascript">
|
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
});
|
|
</script>
|
|
|
|
<div id="content" class="content">
|
|
<main>
|
|
<h2><a class="header" href="#writing-macros" id="writing-macros">Writing macros</a></h2>
|
|
<p>Writing macros can be very complicated. You almost never need to write one, but sometimes you might want to because they are very convenient. Writing macros is interesting because they are almost a different language. To write one, you actually use another macro called <code>macro_rules!</code>. Then you add your macro name and open a <code>{}</code> block. Inside is sort of like a <code>match</code> statement.</p>
|
|
<p>Here's one that only takes <code>()</code>, then just returns 6:</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! give_six {
|
|
() => {
|
|
6
|
|
};
|
|
}
|
|
|
|
fn main() {
|
|
let six = give_six!();
|
|
println!("{}", six);
|
|
}
|
|
</code></pre></pre>
|
|
<p>But it's not the same as a <code>match</code> statement, because a macro actually doesn't compile anything. It just takes an input and gives an output. Then the compiler checks to see if it makes sense. That's why a macro is like "code that writes code". You will remember that a true <code>match</code> statement needs to give the same type, so this won't work:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn main() {
|
|
// ⚠️
|
|
let my_number = 10;
|
|
match my_number {
|
|
10 => println!("You got a ten"),
|
|
_ => 10,
|
|
}
|
|
}
|
|
</code></pre></pre>
|
|
<p>It will complain that you want to return <code>()</code> in one case, and <code>i32</code> in the other.</p>
|
|
<pre><code class="language-text">error[E0308]: `match` arms have incompatible types
|
|
--> src\main.rs:5:14
|
|
|
|
|
3 | / match my_number {
|
|
4 | | 10 => println!("You got a ten"),
|
|
| | ------------------------- this is found to be of type `()`
|
|
5 | | _ => 10,
|
|
| | ^^ expected `()`, found integer
|
|
6 | | }
|
|
| |_____- `match` arms have incompatible types
|
|
</code></pre>
|
|
<p>But a macro doesn't care, because it's just giving an output. It's not a compiler - it's code before code. So you can do this:</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! six_or_print {
|
|
(6) => {
|
|
6
|
|
};
|
|
() => {
|
|
println!("You didn't give me 6.");
|
|
};
|
|
}
|
|
|
|
fn main() {
|
|
let my_number = six_or_print!(6);
|
|
six_or_print!();
|
|
}
|
|
</code></pre></pre>
|
|
<p>This is just fine, and prints <code>You didn't give me 6.</code>. You can also see that it's not a match arm because there's no <code>_</code> case. We can only give it <code>(6)</code>, or <code>()</code>. Anything else will make an error. And the <code>6</code> we give it isn't even an <code>i32</code>, it's just an input 6. You can actually set anything as the input for a macro, because it's just looking at input to see what it gets. For example:</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! might_print {
|
|
(THis is strange input 하하はは哈哈 but it still works) => {
|
|
println!("You guessed the secret message!")
|
|
};
|
|
() => {
|
|
println!("You didn't guess it");
|
|
};
|
|
}
|
|
|
|
fn main() {
|
|
might_print!(THis is strange input 하하はは哈哈 but it still works);
|
|
might_print!();
|
|
}
|
|
</code></pre></pre>
|
|
<p>So this strange macro only responds to two things: <code>()</code> and <code>(THis is strange input 하하はは哈哈 but it still works)</code>. Nothing else. It prints:</p>
|
|
<pre><code class="language-text">You guessed the secret message!
|
|
You didn't guess it
|
|
</code></pre>
|
|
<p>So a macro isn't exactly Rust syntax. But a macro can also understand different types of input that you give it. Take this example:</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! might_print {
|
|
($input:expr) => {
|
|
println!("You gave me: {}", $input);
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
might_print!(6);
|
|
}
|
|
</code></pre></pre>
|
|
<p>This will print <code>You gave me: 6</code>. The <code>$input:expr</code> part is important. It means "for an expression, give it the variable name $input". In macros, variables start with a <code>$</code>. In this macro, if you give it one expression, it will print it. Let's try it out some more:</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! might_print {
|
|
($input:expr) => {
|
|
println!("You gave me: {:?}", $input); // Now we'll use {:?} because we will give it different kinds of expressions
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
might_print!(()); // give it a ()
|
|
might_print!(6); // give it a 6
|
|
might_print!(vec![8, 9, 7, 10]); // give it a vec
|
|
}
|
|
</code></pre></pre>
|
|
<p>This will print:</p>
|
|
<pre><code class="language-text">You gave me: ()
|
|
You gave me: 6
|
|
You gave me: [8, 9, 7, 10]
|
|
</code></pre>
|
|
<p>Also note that we wrote <code>{:?}</code>, but it won't check to see if <code>&input</code> implements <code>Debug</code>. It'll just write the code and try to make it compile, and if it doesn't then it gives an error.</p>
|
|
<p>So what can a macro see besides <code>expr</code>? They are: <code>block | expr | ident | item | lifetime | literal | meta | pat | path | stmt | tt | ty | vis</code>. This is the complicated part. You can see what each of them means <a href="https://doc.rust-lang.org/beta/reference/macros-by-example.html">here</a>, where it says:</p>
|
|
<pre><code class="language-text">item: an Item
|
|
block: a BlockExpression
|
|
stmt: a Statement without the trailing semicolon (except for item statements that require semicolons)
|
|
pat: a Pattern
|
|
expr: an Expression
|
|
ty: a Type
|
|
ident: an IDENTIFIER_OR_KEYWORD
|
|
path: a TypePath style path
|
|
tt: a TokenTree (a single token or tokens in matching delimiters (), [], or {})
|
|
meta: an Attr, the contents of an attribute
|
|
lifetime: a LIFETIME_TOKEN
|
|
vis: a possibly empty Visibility qualifier
|
|
literal: matches -?LiteralExpression
|
|
</code></pre>
|
|
<p>There is another good site called cheats.rs that explains them <a href="https://cheats.rs/#macros-attributes">here</a> and gives examples for each.</p>
|
|
<p>However, for most macros you will use <code>expr</code>, <code>ident</code>, and <code>tt</code>. <code>ident</code> means identifier and is for variable or function names. <code>tt</code> means token tree and sort of means any type of input. Let's try a simple macro with both.</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! check {
|
|
($input1:ident, $input2:expr) => {
|
|
println!(
|
|
"Is {:?} equal to {:?}? {:?}",
|
|
$input1,
|
|
$input2,
|
|
$input1 == $input2
|
|
);
|
|
};
|
|
}
|
|
|
|
fn main() {
|
|
let x = 6;
|
|
let my_vec = vec![7, 8, 9];
|
|
check!(x, 6);
|
|
check!(my_vec, vec![7, 8, 9]);
|
|
check!(x, 10);
|
|
}
|
|
</code></pre></pre>
|
|
<p>So this will take one <code>ident</code> (like a variable name) and an expression and see if they are the same. It prints:</p>
|
|
<pre><code class="language-text">Is 6 equal to 6? true
|
|
Is [7, 8, 9] equal to [7, 8, 9]? true
|
|
Is 6 equal to 10? false
|
|
</code></pre>
|
|
<p>And here's one macro that takes a <code>tt</code> and prints it. It uses a macro called <code>stringify!</code> to make a string first.</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! print_anything {
|
|
($input:tt) => {
|
|
let output = stringify!($input);
|
|
println!("{}", output);
|
|
};
|
|
}
|
|
|
|
fn main() {
|
|
print_anything!(ththdoetd);
|
|
print_anything!(87575oehq75onth);
|
|
}
|
|
</code></pre></pre>
|
|
<p>This prints:</p>
|
|
<pre><code class="language-text">ththdoetd
|
|
87575oehq75onth
|
|
</code></pre>
|
|
<p>But it won't print if we give it something with spaces, commas, etc. It will think that we are giving it more than one item or extra information, so it will be confused.</p>
|
|
<p>This is where macros start to get difficult.</p>
|
|
<p>To give a macro more than one item at a time, we have to use a different syntax. Instead of <code>$input</code>, it will be <code>$($input1),*</code>. This means zero or more (this is what * means), separated by a comma. If you want one or more, use <code>+</code> instead of <code>*</code>.</p>
|
|
<p>Now our macro looks like this:</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! print_anything {
|
|
($($input1:tt),*) => {
|
|
let output = stringify!($($input1),*);
|
|
println!("{}", output);
|
|
};
|
|
}
|
|
|
|
|
|
fn main() {
|
|
print_anything!(ththdoetd, rcofe);
|
|
print_anything!();
|
|
print_anything!(87575oehq75onth, ntohe, 987987o, 097);
|
|
}
|
|
</code></pre></pre>
|
|
<p>So it takes any token tree separated by commas, and uses <code>stringify!</code> to make it into a string. Then it prints it. It prints:</p>
|
|
<pre><code class="language-text">ththdoetd, rcofe
|
|
|
|
87575oehq75onth, ntohe, 987987o, 097
|
|
</code></pre>
|
|
<p>If we used <code>+</code> instead of <code>*</code> it would give an error, because one time we gave it no input. So <code>*</code> is a bit safer option.</p>
|
|
<p>So now we can start to see the power of macros. In this next example we can actually make our own functions:</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! make_a_function {
|
|
($name:ident, $($input:tt),*) => { // First you give it one name for the function, then it checks everything else
|
|
fn $name() {
|
|
let output = stringify!($($input),*); // It makes everything else into a string
|
|
println!("{}", output);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
fn main() {
|
|
make_a_function!(print_it, 5, 5, 6, I); // We want a function called print_it() that prints everything else we give it
|
|
print_it();
|
|
make_a_function!(say_its_nice, this, is, really, nice); // Same here but we change the function name
|
|
say_its_nice();
|
|
}
|
|
</code></pre></pre>
|
|
<p>This prints:</p>
|
|
<pre><code class="language-text">5, 5, 6, I
|
|
this, is, really, nice
|
|
</code></pre>
|
|
<p>So now we can start to understand other macros. You can see that some of the macros we've already been using are pretty simple. Here's the one for <code>write!</code> that we used to write to files:</p>
|
|
<pre><pre class="playground"><code class="language-rust">
|
|
<span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>macro_rules! write {
|
|
($dst:expr, $($arg:tt)*) => ($dst.write_fmt($crate::format_args!($($arg)*)))
|
|
}
|
|
<span class="boring">}
|
|
</span></code></pre></pre>
|
|
<p>So to use it, you enter this:</p>
|
|
<ul>
|
|
<li>an expression (<code>expr</code>) that gets the variable name <code>$dst</code>.</li>
|
|
<li>everything after that. If it wrote <code>$arg:tt</code> then it would only take one, but because it wrote <code>$($arg:tt)*</code> it takes zero, one, or any number.</li>
|
|
</ul>
|
|
<p>Then it takes <code>$dst</code> and uses a method called <code>write_fmt</code> on it. Inside that, it uses another macro called <code>format_args!</code> that takes all <code>$($arg)*</code>, or all the arguments we put in.</p>
|
|
<p>Now let's take a look at the <code>todo!</code> macro. That's the one you use when you want the program to compile but haven't written your code yet. It looks like this:</p>
|
|
<pre><pre class="playground"><code class="language-rust">
|
|
<span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>macro_rules! todo {
|
|
() => (panic!("not yet implemented"));
|
|
($($arg:tt)+) => (panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
|
|
}
|
|
<span class="boring">}
|
|
</span></code></pre></pre>
|
|
<p>This one has two options: you can enter <code>()</code>, or a number of token trees (<code>tt</code>).</p>
|
|
<ul>
|
|
<li>If you enter <code>()</code>, it just uses <code>panic!</code> with a message. So you could actually just write <code>panic!("not yet implemented")</code> instead of <code>todo!</code> and it would be the same.</li>
|
|
<li>If you enter some arguments, it will try to print them. You can see the same <code>format_args!</code> macro inside, which works like <code>println!</code>.</li>
|
|
</ul>
|
|
<p>So if you write this, it will work too:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn not_done() {
|
|
let time = 8;
|
|
let reason = "lack of time";
|
|
todo!("Not done yet because of {}. Check back in {} hours", reason, time);
|
|
}
|
|
|
|
fn main() {
|
|
not_done();
|
|
}
|
|
</code></pre></pre>
|
|
<p>This will print:</p>
|
|
<pre><code class="language-text">thread 'main' panicked at 'not yet implemented: Not done yet because of lack of time. Check back in 8 hours', src/main.rs:4:5
|
|
</code></pre>
|
|
<p>Inside a macro you can even call the same macro. Here's one:</p>
|
|
<pre><pre class="playground"><code class="language-rust">macro_rules! my_macro {
|
|
() => {
|
|
println!("Let's print this.");
|
|
};
|
|
($input:expr) => {
|
|
my_macro!();
|
|
};
|
|
($($input:expr),*) => {
|
|
my_macro!();
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
my_macro!(vec![8, 9, 0]);
|
|
my_macro!(toheteh);
|
|
my_macro!(8, 7, 0, 10);
|
|
my_macro!();
|
|
}
|
|
</code></pre></pre>
|
|
<p>This one takes either <code>()</code>, or one expression, or many expressions. But it ignores all the expressions no matter what you put in, and just calls <code>my_macro!</code> on <code>()</code>. So the output is just <code>Let's print this</code>, four times.</p>
|
|
<p>You can see the same thing in the <code>dbg!</code> macro, which also calls itself.</p>
|
|
<pre><pre class="playground"><code class="language-rust">
|
|
<span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>macro_rules! dbg {
|
|
() => {
|
|
$crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!()); //$crate means the crate that it's in.
|
|
};
|
|
($val:expr) => {
|
|
// Use of `match` here is intentional because it affects the lifetimes
|
|
// of temporaries - https://stackoverflow.com/a/48732525/1063961
|
|
match $val {
|
|
tmp => {
|
|
$crate::eprintln!("[{}:{}] {} = {:#?}",
|
|
$crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);
|
|
tmp
|
|
}
|
|
}
|
|
};
|
|
// Trailing comma with single argument is ignored
|
|
($val:expr,) => { $crate::dbg!($val) };
|
|
($($val:expr),+ $(,)?) => {
|
|
($($crate::dbg!($val)),+,)
|
|
};
|
|
}
|
|
<span class="boring">}
|
|
</span></code></pre></pre>
|
|
<p>(<code>eprintln!</code> is the same as <code>println!</code> except it prints to <code>io::stderr</code> instead of <code>io::stdout</code>. There is also <code>eprint!</code> that doesn't add a new line)</p>
|
|
<p>So we can try this out ourself.</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn main() {
|
|
dbg!();
|
|
}
|
|
</code></pre></pre>
|
|
<p>That matches the first arm, so it will print the file name and line name with the <code>file!</code> and <code>line!</code> macros. It prints <code>[src/main.rs:2]</code>.</p>
|
|
<p>Let's try it with this:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn main() {
|
|
dbg!(vec![8, 9, 10]);
|
|
}
|
|
</code></pre></pre>
|
|
<p>This will match the next arm, because it's one expression. It will then call the input <code>tmp</code> and use this code: <code> $crate::eprintln!("[{}:{}] {} = {:#?}", $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);</code>. So it will print with <code>file!</code> and <code>line!</code>, then <code>$val</code> made into a <code>String</code>, and pretty print with <code>{:#?}</code> for <code>tmp</code>. So for our input it will write this:</p>
|
|
<pre><code class="language-text">[src/main.rs:2] vec![8, 9, 10] = [
|
|
8,
|
|
9,
|
|
10,
|
|
]
|
|
</code></pre>
|
|
<p>And for the rest of it it just calls <code>dbg!</code> on itself even if you put in an extra comma.</p>
|
|
<p>As you can see, macros are very complicated! Usually you only want a macro to automatically do something that a simple function can't do very well. The best way to learn about macros is to look at other macro examples. Not many people can quickly write macros without problems. So don't think that you need to know everything about macros to know how to write in Rust. But if you read other macros, and change them a little, you can easily borrow their power. Then you might start to get comfortable with writing your own.</p>
|
|
<h1><a class="header" href="#part-2---rust-on-your-computer" id="part-2---rust-on-your-computer">Part 2 - Rust on your computer</a></h1>
|
|
<p>You saw that we can learn almost anything in Rust just using the Playground. But if you learned everything so far, you will probably want Rust on your computer now. There are always things that you can't do with the Playground like using files or code in more than just one file. Some other things you need Rust on your computer for are input and flags. But most important is that with Rust on your computer you can use crates. We already learned about crates, but in the Playground you could only use the most popular ones. But with Rust on your computer you can use any crate in your program.</p>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
|
|
<a rel="prev" href="Chapter_63.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
|
|
|
|
<a rel="next" href="Chapter_65.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
|
|
<div style="clear: both"></div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
|
|
<a rel="prev" href="Chapter_63.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
|
|
|
|
<a rel="next" href="Chapter_65.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
</nav>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
window.playground_copyable = true;
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
|
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
<!-- Custom JS scripts -->
|
|
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|