mirror of
https://github.com/rust-unofficial/patterns
synced 2024-11-12 07:10:30 +00:00
3729 lines
195 KiB
HTML
3729 lines
195 KiB
HTML
<!DOCTYPE HTML>
|
||
<html lang="en" class="sidebar-visible no-js rust">
|
||
<head>
|
||
<!-- Book generated using mdBook -->
|
||
<meta charset="UTF-8">
|
||
<title>Rust Design Patterns</title>
|
||
<meta name="robots" content="noindex" />
|
||
<!-- Custom HTML head -->
|
||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||
<meta name="description" content="A catalogue of Rust design patterns, anti-patterns and idioms">
|
||
<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" : "rust";
|
||
</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('rust')
|
||
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="intro.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="translations.html"><strong aria-hidden="true">1.1.</strong> Translations</a></li></ol></li><li class="chapter-item expanded "><a href="idioms/index.html"><strong aria-hidden="true">2.</strong> Idioms</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="idioms/coercion-arguments.html"><strong aria-hidden="true">2.1.</strong> Use borrowed types for arguments</a></li><li class="chapter-item expanded "><a href="idioms/concat-format.html"><strong aria-hidden="true">2.2.</strong> Concatenating Strings with format!</a></li><li class="chapter-item expanded "><a href="idioms/ctor.html"><strong aria-hidden="true">2.3.</strong> Constructor</a></li><li class="chapter-item expanded "><a href="idioms/default.html"><strong aria-hidden="true">2.4.</strong> The Default Trait</a></li><li class="chapter-item expanded "><a href="idioms/deref.html"><strong aria-hidden="true">2.5.</strong> Collections Are Smart Pointers</a></li><li class="chapter-item expanded "><a href="idioms/dtor-finally.html"><strong aria-hidden="true">2.6.</strong> Finalisation in Destructors</a></li><li class="chapter-item expanded "><a href="idioms/mem-replace.html"><strong aria-hidden="true">2.7.</strong> mem::{take(), replace()}</a></li><li class="chapter-item expanded "><a href="idioms/on-stack-dyn-dispatch.html"><strong aria-hidden="true">2.8.</strong> On-Stack Dynamic Dispatch</a></li><li class="chapter-item expanded "><a href="idioms/ffi/intro.html"><strong aria-hidden="true">2.9.</strong> Foreign function interface (FFI)</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="idioms/ffi/errors.html"><strong aria-hidden="true">2.9.1.</strong> Idiomatic Errors</a></li><li class="chapter-item expanded "><a href="idioms/ffi/accepting-strings.html"><strong aria-hidden="true">2.9.2.</strong> Accepting Strings</a></li><li class="chapter-item expanded "><a href="idioms/ffi/passing-strings.html"><strong aria-hidden="true">2.9.3.</strong> Passing Strings</a></li></ol></li><li class="chapter-item expanded "><a href="idioms/option-iter.html"><strong aria-hidden="true">2.10.</strong> Iterating over an Option</a></li><li class="chapter-item expanded "><a href="idioms/pass-var-to-closure.html"><strong aria-hidden="true">2.11.</strong> Pass Variables to Closure</a></li><li class="chapter-item expanded "><a href="idioms/priv-extend.html"><strong aria-hidden="true">2.12.</strong> Privacy For Extensibility</a></li><li class="chapter-item expanded "><a href="idioms/rustdoc-init.html"><strong aria-hidden="true">2.13.</strong> Easy doc initialization</a></li><li class="chapter-item expanded "><a href="idioms/temporary-mutability.html"><strong aria-hidden="true">2.14.</strong> Temporary mutability</a></li></ol></li><li class="chapter-item expanded "><a href="patterns/index.html"><strong aria-hidden="true">3.</strong> Design Patterns</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="patterns/behavioural/intro.html"><strong aria-hidden="true">3.1.</strong> Behavioural</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="patterns/behavioural/command.html"><strong aria-hidden="true">3.1.1.</strong> Command</a></li><li class="chapter-item expanded "><a href="patterns/behavioural/interpreter.html"><strong aria-hidden="true">3.1.2.</strong> Interpreter</a></li><li class="chapter-item expanded "><a href="patterns/behavioural/newtype.html"><strong aria-hidden="true">3.1.3.</strong> Newtype</a></li><li class="chapter-item expanded "><a href="patterns/behavioural/RAII.html"><strong aria-hidden="true">3.1.4.</strong> RAII Guards</a></li><li class="chapter-item expanded "><a href="patterns/behavioural/strategy.html"><strong aria-hidden="true">3.1.5.</strong> Strategy</a></li><li class="chapter-item expanded "><a href="patterns/behavioural/visitor.html"><strong aria-hidden="true">3.1.6.</strong> Visitor</a></li></ol></li><li class="chapter-item expanded "><a href="patterns/creational/intro.html"><strong aria-hidden="true">3.2.</strong> Creational</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="patterns/creational/builder.html"><strong aria-hidden="true">3.2.1.</strong> Builder</a></li><li class="chapter-item expanded "><a href="patterns/creational/fold.html"><strong aria-hidden="true">3.2.2.</strong> Fold</a></li></ol></li><li class="chapter-item expanded "><a href="patterns/structural/intro.html"><strong aria-hidden="true">3.3.</strong> Structural</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="patterns/structural/compose-structs.html"><strong aria-hidden="true">3.3.1.</strong> Compose Structs</a></li><li class="chapter-item expanded "><a href="patterns/structural/small-crates.html"><strong aria-hidden="true">3.3.2.</strong> Prefer Small Crates</a></li><li class="chapter-item expanded "><a href="patterns/structural/unsafe-mods.html"><strong aria-hidden="true">3.3.3.</strong> Contain unsafety in small modules</a></li></ol></li><li class="chapter-item expanded "><a href="patterns/ffi/intro.html"><strong aria-hidden="true">3.4.</strong> Foreign function interface (FFI)</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="patterns/ffi/export.html"><strong aria-hidden="true">3.4.1.</strong> Object-Based APIs</a></li><li class="chapter-item expanded "><a href="patterns/ffi/wrappers.html"><strong aria-hidden="true">3.4.2.</strong> Type Consolidation into Wrappers</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="anti_patterns/index.html"><strong aria-hidden="true">4.</strong> Anti-patterns</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="anti_patterns/borrow_clone.html"><strong aria-hidden="true">4.1.</strong> Clone to satisfy the borrow checker</a></li><li class="chapter-item expanded "><a href="anti_patterns/deny-warnings.html"><strong aria-hidden="true">4.2.</strong> #[deny(warnings)]</a></li><li class="chapter-item expanded "><a href="anti_patterns/deref.html"><strong aria-hidden="true">4.3.</strong> Deref Polymorphism</a></li></ol></li><li class="chapter-item expanded "><a href="functional/index.html"><strong aria-hidden="true">5.</strong> Functional Programming</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="functional/paradigms.html"><strong aria-hidden="true">5.1.</strong> Programming paradigms</a></li><li class="chapter-item expanded "><a href="functional/generics-type-classes.html"><strong aria-hidden="true">5.2.</strong> Generics as Type Classes</a></li></ol></li><li class="chapter-item expanded "><a href="additional_resources/index.html"><strong aria-hidden="true">6.</strong> Additional Resources</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="additional_resources/design-principles.html"><strong aria-hidden="true">6.1.</strong> Design principles</a></li></ol></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</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust (default)</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">Rust Design Patterns</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>
|
||
<a href="https://github.com/rust-unofficial/patterns" title="Git repository" aria-label="Git repository">
|
||
<i id="git-repository-button" class="fa fa-github"></i>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="search-wrapper" class="hidden">
|
||
<form id="searchbar-outer" class="searchbar-outer">
|
||
<input type="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>
|
||
<h1 id="introduction"><a class="header" href="#introduction">Introduction</a></h1>
|
||
<h2 id="participation"><a class="header" href="#participation">Participation</a></h2>
|
||
<p>If you are interested in contributing to this book, check out the
|
||
<a href="https://github.com/rust-unofficial/patterns/blob/master/CONTRIBUTING.md">contribution guidelines</a>.</p>
|
||
<h2 id="design-patterns"><a class="header" href="#design-patterns">Design patterns</a></h2>
|
||
<p>In software development, we often come across problems that share
|
||
similarities regardless of the environment they appear in. Although the
|
||
implementation details are crucial to solve the task at hand, we may
|
||
abstract from these particularities to find the common practices that
|
||
are generically applicable.</p>
|
||
<p>Design patterns are a collection of reusable and tested solutions to
|
||
recurring problems in engineering. They make our software more modular,
|
||
maintainable, and extensible. Moreover, these patterns provide a common
|
||
language for developers to use, making them an excellent tool for effective
|
||
communication when problem-solving in teams.</p>
|
||
<h2 id="design-patterns-in-rust"><a class="header" href="#design-patterns-in-rust">Design patterns in Rust</a></h2>
|
||
<p>There are many problems that share the same form.
|
||
Due to the fact that Rust is not object-oriented, design patterns vary with
|
||
respect to other object-oriented programming languages.
|
||
While the details are different, since they have the same form they can be
|
||
solved using the same fundamental methods:</p>
|
||
<ul>
|
||
<li><a href="./patterns/index.html">Design patterns</a> are methods to solve common problems
|
||
when writing software.</li>
|
||
<li><a href="./anti_patterns/index.html">Anti-patterns</a> are methods to solve these same
|
||
common problems. However, while design patterns give us benefits,
|
||
anti-patterns create more problems.</li>
|
||
<li><a href="./idioms/index.html">Idioms</a> are guidelines to follow when coding.
|
||
They are social norms of the community.
|
||
You can break them, but if you do you should have a good reason for it.</li>
|
||
</ul>
|
||
<p>TODO: Mention why Rust is a bit special - functional elements, type system,
|
||
borrow checker</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="translations"><a class="header" href="#translations">Translations</a></h1>
|
||
<ul>
|
||
<li><a href="https://fomalhauthmj.github.io/patterns/">简体中文</a></li>
|
||
</ul>
|
||
<p>If you want to add a translation, please open an issue in the
|
||
<a href="https://github.com/rust-unofficial/patterns">main repository</a>.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="idioms"><a class="header" href="#idioms">Idioms</a></h1>
|
||
<p><a href="https://en.wikipedia.org/wiki/Programming_idiom">Idioms</a> are commonly used
|
||
styles and patterns largely agreed upon by a community. They are guidelines.
|
||
Writing idiomatic code allows other developers to understand what is happening
|
||
because they are familiar with the form that it has.</p>
|
||
<p>The computer understands the machine code that is generated by the compiler.
|
||
The language is therefore mostly beneficial to the developer.
|
||
So, since we have this abstraction layer, why not put it to good use and make
|
||
it simple?</p>
|
||
<p>Remember the <a href="https://en.wikipedia.org/wiki/KISS_principle">KISS principle</a>:
|
||
"Keep It Simple, Stupid". It claims that "most systems work best if they are
|
||
kept simple rather than made complicated; therefore, simplicity should be a key
|
||
goal in design, and unnecessary complexity should be avoided".</p>
|
||
<blockquote>
|
||
<p>Code is there for humans, not computers, to understand.</p>
|
||
</blockquote>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="use-borrowed-types-for-arguments"><a class="header" href="#use-borrowed-types-for-arguments">Use borrowed types for arguments</a></h1>
|
||
<h2 id="description"><a class="header" href="#description">Description</a></h2>
|
||
<p>Using a target of a deref coercion can increase the flexibility of your code
|
||
when you are deciding which argument type to use for a function argument.
|
||
In this way, the function will accept more input types.</p>
|
||
<p>This is not limited to slice-able or fat pointer types.
|
||
In fact, you should always prefer using the <strong>borrowed type</strong> over
|
||
<strong>borrowing the owned type</strong>.
|
||
Such as <code>&str</code> over <code>&String</code>, <code>&[T]</code> over <code>&Vec<T></code>, or <code>&T</code> over <code>&Box<T></code>.</p>
|
||
<p>Using borrowed types you can avoid layers of indirection for those instances
|
||
where the owned type already provides a layer of indirection. For instance, a
|
||
<code>String</code> has a layer of indirection, so a <code>&String</code> will have two layers of
|
||
indirection. We can avoid this by using <code>&str</code> instead, and letting <code>&String</code>
|
||
coerce to a <code>&str</code> whenever the function is invoked.</p>
|
||
<h2 id="example"><a class="header" href="#example">Example</a></h2>
|
||
<p>For this example, we will illustrate some differences for using <code>&String</code> as a
|
||
function argument versus using a <code>&str</code>, but the ideas apply as well to using
|
||
<code>&Vec<T></code> versus using a <code>&[T]</code> or using a <code>&Box<T></code> versus a <code>&T</code>.</p>
|
||
<p>Consider an example where we wish to determine if a word contains three
|
||
consecutive vowels. We don't need to own the string to determine this, so we
|
||
will take a reference.</p>
|
||
<p>The code might look something like this:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">fn three_vowels(word: &String) -> bool {
|
||
let mut vowel_count = 0;
|
||
for c in word.chars() {
|
||
match c {
|
||
'a' | 'e' | 'i' | 'o' | 'u' => {
|
||
vowel_count += 1;
|
||
if vowel_count >= 3 {
|
||
return true
|
||
}
|
||
}
|
||
_ => vowel_count = 0
|
||
}
|
||
}
|
||
false
|
||
}
|
||
|
||
fn main() {
|
||
let ferris = "Ferris".to_string();
|
||
let curious = "Curious".to_string();
|
||
println!("{}: {}", ferris, three_vowels(&ferris));
|
||
println!("{}: {}", curious, three_vowels(&curious));
|
||
|
||
// This works fine, but the following two lines would fail:
|
||
// println!("Ferris: {}", three_vowels("Ferris"));
|
||
// println!("Curious: {}", three_vowels("Curious"));
|
||
|
||
}
|
||
</code></pre></pre>
|
||
<p>This works fine because we are passing a <code>&String</code> type as a parameter.
|
||
If we comment in the last two lines this example fails because a <code>&str</code> type
|
||
will not coerce to a <code>&String</code> type. We can fix this by simply modifying the
|
||
type for our argument.</p>
|
||
<p>For instance, if we change our function declaration to:</p>
|
||
<pre><code class="language-rust ignore">fn three_vowels(word: &str) -> bool {
|
||
</code></pre>
|
||
<p>then both versions will compile and print the same output.</p>
|
||
<pre><code class="language-bash">Ferris: false
|
||
Curious: true
|
||
</code></pre>
|
||
<p>But wait, that's not all! There is more to this story.
|
||
It's likely that you may say to yourself: that doesn't matter, I will never be
|
||
using a <code>&'static str</code> as an input anyways (as we did when we used <code>"Ferris"</code>).
|
||
Even ignoring this special example, you may still find that using <code>&str</code> will
|
||
give you more flexibility than using a <code>&String</code>.</p>
|
||
<p>Let's now take an example where someone gives us a sentence, and we want to
|
||
determine if any of the words in the sentence contain three consecutive vowels.
|
||
We probably should make use of the function we have already defined and simply
|
||
feed in each word from the sentence.</p>
|
||
<p>An example of this could look like this:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">fn three_vowels(word: &str) -> bool {
|
||
let mut vowel_count = 0;
|
||
for c in word.chars() {
|
||
match c {
|
||
'a' | 'e' | 'i' | 'o' | 'u' => {
|
||
vowel_count += 1;
|
||
if vowel_count >= 3 {
|
||
return true
|
||
}
|
||
}
|
||
_ => vowel_count = 0
|
||
}
|
||
}
|
||
false
|
||
}
|
||
|
||
fn main() {
|
||
let sentence_string =
|
||
"Once upon a time, there was a friendly curious crab named Ferris".to_string();
|
||
for word in sentence_string.split(' ') {
|
||
if three_vowels(word) {
|
||
println!("{} has three consecutive vowels!", word);
|
||
}
|
||
}
|
||
}
|
||
</code></pre></pre>
|
||
<p>Running this example using our function declared with an argument type <code>&str</code>
|
||
will yield</p>
|
||
<pre><code class="language-bash">curious has three consecutive vowels!
|
||
</code></pre>
|
||
<p>However, this example will not run when our function is declared with an
|
||
argument type <code>&String</code>. This is because string slices are a <code>&str</code> and not a
|
||
<code>&String</code> which would require an allocation to be converted to <code>&String</code> which
|
||
is not implicit, whereas converting from <code>String</code> to <code>&str</code> is cheap and implicit.</p>
|
||
<h2 id="see-also"><a class="header" href="#see-also">See also</a></h2>
|
||
<ul>
|
||
<li><a href="https://doc.rust-lang.org/reference/type-coercions.html">Rust Language Reference on Type Coercions</a></li>
|
||
<li>For more discussion on how to handle <code>String</code> and <code>&str</code> see
|
||
<a href="https://web.archive.org/web/20201112023149/https://hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html">this blog series (2015)</a>
|
||
by Herman J. Radtke III</li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="concatenating-strings-with-format"><a class="header" href="#concatenating-strings-with-format">Concatenating strings with <code>format!</code></a></h1>
|
||
<h2 id="description-1"><a class="header" href="#description-1">Description</a></h2>
|
||
<p>It is possible to build up strings using the <code>push</code> and <code>push_str</code> methods on a
|
||
mutable <code>String</code>, or using its <code>+</code> operator. However, it is often more
|
||
convenient to use <code>format!</code>, especially where there is a mix of literal and
|
||
non-literal strings.</p>
|
||
<h2 id="example-1"><a class="header" href="#example-1">Example</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>fn say_hello(name: &str) -> String {
|
||
// We could construct the result string manually.
|
||
// let mut result = "Hello ".to_owned();
|
||
// result.push_str(name);
|
||
// result.push('!');
|
||
// result
|
||
|
||
// But using format! is better.
|
||
format!("Hello {}!", name)
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="advantages"><a class="header" href="#advantages">Advantages</a></h2>
|
||
<p>Using <code>format!</code> is usually the most succinct and readable way to combine strings.</p>
|
||
<h2 id="disadvantages"><a class="header" href="#disadvantages">Disadvantages</a></h2>
|
||
<p>It is usually not the most efficient way to combine strings - a series of <code>push</code>
|
||
operations on a mutable string is usually the most efficient (especially if the
|
||
string has been pre-allocated to the expected size).</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="constructors"><a class="header" href="#constructors">Constructors</a></h1>
|
||
<h2 id="description-2"><a class="header" href="#description-2">Description</a></h2>
|
||
<p>Rust does not have constructors as a language construct. Instead, the
|
||
convention is to use an <a href="https://doc.rust-lang.org/stable/book/ch05-03-method-syntax.html#associated-functions">associated function</a> <code>new</code> to create an object:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>/// Time in seconds.
|
||
///
|
||
/// # Example
|
||
///
|
||
/// ```
|
||
/// let s = Second::new(42);
|
||
/// assert_eq!(42, s.value());
|
||
/// ```
|
||
pub struct Second {
|
||
value: u64
|
||
}
|
||
|
||
impl Second {
|
||
// Constructs a new instance of [`Second`].
|
||
// Note this is an associated function - no self.
|
||
pub fn new(value: u64) -> Self {
|
||
Self { value }
|
||
}
|
||
|
||
/// Returns the value in seconds.
|
||
pub fn value(&self) -> u64 {
|
||
self.value
|
||
}
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="default-constructors"><a class="header" href="#default-constructors">Default Constructors</a></h2>
|
||
<p>Rust supports default constructors with the <a href="https://doc.rust-lang.org/stable/std/default/trait.Default.html"><code>Default</code></a> trait:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>/// Time in seconds.
|
||
///
|
||
/// # Example
|
||
///
|
||
/// ```
|
||
/// let s = Second::default();
|
||
/// assert_eq!(0, s.value());
|
||
/// ```
|
||
pub struct Second {
|
||
value: u64
|
||
}
|
||
|
||
impl Second {
|
||
/// Returns the value in seconds.
|
||
pub fn value(&self) -> u64 {
|
||
self.value
|
||
}
|
||
}
|
||
|
||
impl Default for Second {
|
||
fn default() -> Self {
|
||
Self { value: 0 }
|
||
}
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<p><code>Default</code> can also be derived if all types of all fields implement <code>Default</code>,
|
||
like they do with <code>Second</code>:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>/// Time in seconds.
|
||
///
|
||
/// # Example
|
||
///
|
||
/// ```
|
||
/// let s = Second::default();
|
||
/// assert_eq!(0, s.value());
|
||
/// ```
|
||
#[derive(Default)]
|
||
pub struct Second {
|
||
value: u64
|
||
}
|
||
|
||
impl Second {
|
||
/// Returns the value in seconds.
|
||
pub fn value(&self) -> u64 {
|
||
self.value
|
||
}
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<p><strong>Note:</strong> When implementing <code>Default</code> for a type, it is neither required nor
|
||
recommended to also provide an associated function <code>new</code> without arguments.</p>
|
||
<p><strong>Hint:</strong> The advantage of implementing or deriving <code>Default</code> is that your type
|
||
can now be used where a <code>Default</code> implementation is required, most prominently,
|
||
any of the <a href="https://doc.rust-lang.org/stable/std/?search=or_default"><code>*or_default</code> functions in the standard library</a>.</p>
|
||
<h2 id="see-also-1"><a class="header" href="#see-also-1">See also</a></h2>
|
||
<ul>
|
||
<li>
|
||
<p>The <a href="idioms/default.html">default idiom</a> for a more in-depth description of the
|
||
<code>Default</code> trait.</p>
|
||
</li>
|
||
<li>
|
||
<p>The <a href="idioms/../patterns/creational/builder.html">builder pattern</a> for constructing
|
||
objects where there are multiple configurations.</p>
|
||
</li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="the-default-trait"><a class="header" href="#the-default-trait">The <code>Default</code> Trait</a></h1>
|
||
<h2 id="description-3"><a class="header" href="#description-3">Description</a></h2>
|
||
<p>Many types in Rust have a <a href="idioms/ctor.html">constructor</a>. However, this is <em>specific</em> to the
|
||
type; Rust cannot abstract over "everything that has a <code>new()</code> method". To
|
||
allow this, the <a href="https://doc.rust-lang.org/stable/std/default/trait.Default.html"><code>Default</code></a> trait was conceived, which can be used with
|
||
containers and other generic types (e.g. see <a href="https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_or_default"><code>Option::unwrap_or_default()</code></a>).
|
||
Notably, some containers already implement it where applicable.</p>
|
||
<p>Not only do one-element containers like <code>Cow</code>, <code>Box</code> or <code>Arc</code> implement
|
||
<code>Default</code> for contained <code>Default</code> types, one can automatically
|
||
<code>#[derive(Default)]</code> for structs whose fields all implement it, so the more
|
||
types implement <code>Default</code>, the more useful it becomes.</p>
|
||
<p>On the other hand, constructors can take multiple arguments, while the
|
||
<code>default()</code> method does not. There can even be multiple constructors with
|
||
different names, but there can only be one <code>Default</code> implementation per type.</p>
|
||
<h2 id="example-2"><a class="header" href="#example-2">Example</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">use std::{path::PathBuf, time::Duration};
|
||
|
||
// note that we can simply auto-derive Default here.
|
||
#[derive(Default, Debug, PartialEq)]
|
||
struct MyConfiguration {
|
||
// Option defaults to None
|
||
output: Option<PathBuf>,
|
||
// Vecs default to empty vector
|
||
search_path: Vec<PathBuf>,
|
||
// Duration defaults to zero time
|
||
timeout: Duration,
|
||
// bool defaults to false
|
||
check: bool,
|
||
}
|
||
|
||
impl MyConfiguration {
|
||
// add setters here
|
||
}
|
||
|
||
fn main() {
|
||
// construct a new instance with default values
|
||
let mut conf = MyConfiguration::default();
|
||
// do something with conf here
|
||
conf.check = true;
|
||
println!("conf = {:#?}", conf);
|
||
|
||
// partial initialization with default values, creates the same instance
|
||
let conf1 = MyConfiguration {
|
||
check: true,
|
||
..Default::default()
|
||
};
|
||
assert_eq!(conf, conf1);
|
||
}
|
||
</code></pre></pre>
|
||
<h2 id="see-also-2"><a class="header" href="#see-also-2">See also</a></h2>
|
||
<ul>
|
||
<li>The <a href="idioms/ctor.html">constructor</a> idiom is another way to generate instances that may or may
|
||
not be "default"</li>
|
||
<li>The <a href="https://doc.rust-lang.org/stable/std/default/trait.Default.html"><code>Default</code></a> documentation (scroll down for the list of implementors)</li>
|
||
<li><a href="https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_or_default"><code>Option::unwrap_or_default()</code></a></li>
|
||
<li><a href="https://crates.io/crates/derive-new/"><code>derive(new)</code></a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="collections-are-smart-pointers"><a class="header" href="#collections-are-smart-pointers">Collections are smart pointers</a></h1>
|
||
<h2 id="description-4"><a class="header" href="#description-4">Description</a></h2>
|
||
<p>Use the <code>Deref</code> trait to treat collections like smart pointers, offering owning
|
||
and borrowed views of data.</p>
|
||
<h2 id="example-3"><a class="header" href="#example-3">Example</a></h2>
|
||
<pre><code class="language-rust ignore">use std::ops::Deref;
|
||
|
||
struct Vec<T> {
|
||
data: RawVec<T>,
|
||
//..
|
||
}
|
||
|
||
impl<T> Deref for Vec<T> {
|
||
type Target = [T];
|
||
|
||
fn deref(&self) -> &[T] {
|
||
//..
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>A <code>Vec<T></code> is an owning collection of <code>T</code>s, a slice (<code>&[T]</code>) is a borrowed
|
||
collection of <code>T</code>s. Implementing <code>Deref</code> for <code>Vec</code> allows implicit dereferencing
|
||
from <code>&Vec<T></code> to <code>&[T]</code> and includes the relationship in auto-derefencing
|
||
searches. Most methods you might expect to be implemented for <code>Vec</code>s are instead
|
||
implemented for slices.</p>
|
||
<p>See also <code>String</code> and <code>&str</code>.</p>
|
||
<h2 id="motivation"><a class="header" href="#motivation">Motivation</a></h2>
|
||
<p>Ownership and borrowing are key aspects of the Rust language. Data structures
|
||
must account for these semantics properly in order to give a good user
|
||
experience. When implementing a data structure which owns its data, offering a
|
||
borrowed view of that data allows for more flexible APIs.</p>
|
||
<h2 id="advantages-1"><a class="header" href="#advantages-1">Advantages</a></h2>
|
||
<p>Most methods can be implemented only for the borrowed view, they are then
|
||
implicitly available for the owning view.</p>
|
||
<p>Gives clients a choice between borrowing or taking ownership of data.</p>
|
||
<h2 id="disadvantages-1"><a class="header" href="#disadvantages-1">Disadvantages</a></h2>
|
||
<p>Methods and traits only available via dereferencing are not taken into account
|
||
when bounds checking, so generic programming with data structures using this
|
||
pattern can get complex (see the <code>Borrow</code> and <code>AsRef</code> traits, etc.).</p>
|
||
<h2 id="discussion"><a class="header" href="#discussion">Discussion</a></h2>
|
||
<p>Smart pointers and collections are analogous: a smart pointer points to a single
|
||
object, whereas a collection points to many objects. From the point of view of
|
||
the type system there is little difference between the two. A collection owns
|
||
its data if the only way to access each datum is via the collection and the
|
||
collection is responsible for deleting the data (even in cases of shared
|
||
ownership, some kind of borrowed view may be appropriate). If a collection owns
|
||
its data, it is usually useful to provide a view of the data as borrowed so that
|
||
it can be referenced multiple times.</p>
|
||
<p>Most smart pointers (e.g., <code>Foo<T></code>) implement <code>Deref<Target=T></code>. However,
|
||
collections will usually dereference to a custom type. <code>[T]</code> and <code>str</code> have some
|
||
language support, but in the general case, this is not necessary. <code>Foo<T></code> can
|
||
implement <code>Deref<Target=Bar<T>></code> where <code>Bar</code> is a dynamically sized type and
|
||
<code>&Bar<T></code> is a borrowed view of the data in <code>Foo<T></code>.</p>
|
||
<p>Commonly, ordered collections will implement <code>Index</code> for <code>Range</code>s to provide
|
||
slicing syntax. The target will be the borrowed view.</p>
|
||
<h2 id="see-also-3"><a class="header" href="#see-also-3">See also</a></h2>
|
||
<p><a href="idioms/../anti_patterns/deref.html">Deref polymorphism anti-pattern</a>.</p>
|
||
<p><a href="https://doc.rust-lang.org/std/ops/trait.Deref.html">Documentation for <code>Deref</code> trait</a>.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="finalisation-in-destructors"><a class="header" href="#finalisation-in-destructors">Finalisation in destructors</a></h1>
|
||
<h2 id="description-5"><a class="header" href="#description-5">Description</a></h2>
|
||
<p>Rust does not provide the equivalent to <code>finally</code> blocks - code that will be
|
||
executed no matter how a function is exited. Instead, an object's destructor can
|
||
be used to run code that must be run before exit.</p>
|
||
<h2 id="example-4"><a class="header" href="#example-4">Example</a></h2>
|
||
<pre><code class="language-rust ignore">fn bar() -> Result<(), ()> {
|
||
// These don't need to be defined inside the function.
|
||
struct Foo;
|
||
|
||
// Implement a destructor for Foo.
|
||
impl Drop for Foo {
|
||
fn drop(&mut self) {
|
||
println!("exit");
|
||
}
|
||
}
|
||
|
||
// The dtor of _exit will run however the function `bar` is exited.
|
||
let _exit = Foo;
|
||
// Implicit return with `?` operator.
|
||
baz()?;
|
||
// Normal return.
|
||
Ok(())
|
||
}
|
||
</code></pre>
|
||
<h2 id="motivation-1"><a class="header" href="#motivation-1">Motivation</a></h2>
|
||
<p>If a function has multiple return points, then executing code on exit becomes
|
||
difficult and repetitive (and thus bug-prone). This is especially the case where
|
||
return is implicit due to a macro. A common case is the <code>?</code> operator which
|
||
returns if the result is an <code>Err</code>, but continues if it is <code>Ok</code>. <code>?</code> is used as
|
||
an exception handling mechanism, but unlike Java (which has <code>finally</code>), there is
|
||
no way to schedule code to run in both the normal and exceptional cases.
|
||
Panicking will also exit a function early.</p>
|
||
<h2 id="advantages-2"><a class="header" href="#advantages-2">Advantages</a></h2>
|
||
<p>Code in destructors will (nearly) be always run - copes with panics, early
|
||
returns, etc.</p>
|
||
<h2 id="disadvantages-2"><a class="header" href="#disadvantages-2">Disadvantages</a></h2>
|
||
<p>It is not guaranteed that destructors will run. For example, if there is an
|
||
infinite loop in a function or if running a function crashes before exit.
|
||
Destructors are also not run in the case of a panic in an already panicking
|
||
thread. Therefore, destructors cannot be relied on as finalizers where it is
|
||
absolutely essential that finalisation happens.</p>
|
||
<p>This pattern introduces some hard to notice, implicit code. Reading a function
|
||
gives no clear indication of destructors to be run on exit. This can make
|
||
debugging tricky.</p>
|
||
<p>Requiring an object and <code>Drop</code> impl just for finalisation is heavy on boilerplate.</p>
|
||
<h2 id="discussion-1"><a class="header" href="#discussion-1">Discussion</a></h2>
|
||
<p>There is some subtlety about how exactly to store the object used as a
|
||
finalizer. It must be kept alive until the end of the function and must then be
|
||
destroyed. The object must always be a value or uniquely owned pointer (e.g.,
|
||
<code>Box<Foo></code>). If a shared pointer (such as <code>Rc</code>) is used, then the finalizer can
|
||
be kept alive beyond the lifetime of the function. For similar reasons, the
|
||
finalizer should not be moved or returned.</p>
|
||
<p>The finalizer must be assigned into a variable, otherwise it will be destroyed
|
||
immediately, rather than when it goes out of scope. The variable name must start
|
||
with <code>_</code> if the variable is only used as a finalizer, otherwise the compiler
|
||
will warn that the finalizer is never used. However, do not call the variable
|
||
<code>_</code> with no suffix - in that case it will be destroyed immediately.</p>
|
||
<p>In Rust, destructors are run when an object goes out of scope. This happens
|
||
whether we reach the end of block, there is an early return, or the program
|
||
panics. When panicking, Rust unwinds the stack running destructors for each
|
||
object in each stack frame. So, destructors get called even if the panic happens
|
||
in a function being called.</p>
|
||
<p>If a destructor panics while unwinding, there is no good action to take, so Rust
|
||
aborts the thread immediately, without running further destructors. This means
|
||
that destructors are not absolutely guaranteed to run. It also means that you
|
||
must take extra care in your destructors not to panic, since it could leave
|
||
resources in an unexpected state.</p>
|
||
<h2 id="see-also-4"><a class="header" href="#see-also-4">See also</a></h2>
|
||
<p><a href="idioms/../patterns/behavioural/RAII.html">RAII guards</a>.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="memtake_-replace_-to-keep-owned-values-in-changed-enums"><a class="header" href="#memtake_-replace_-to-keep-owned-values-in-changed-enums"><code>mem::{take(_), replace(_)}</code> to keep owned values in changed enums</a></h1>
|
||
<h2 id="description-6"><a class="header" href="#description-6">Description</a></h2>
|
||
<p>Say we have a <code>&mut MyEnum</code> which has (at least) two variants,
|
||
<code>A { name: String, x: u8 }</code> and <code>B { name: String }</code>. Now we want to change
|
||
<code>MyEnum::A</code> to a <code>B</code> if <code>x</code> is zero, while keeping <code>MyEnum::B</code> intact.</p>
|
||
<p>We can do this without cloning the <code>name</code>.</p>
|
||
<h2 id="example-5"><a class="header" href="#example-5">Example</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>use std::mem;
|
||
|
||
enum MyEnum {
|
||
A { name: String, x: u8 },
|
||
B { name: String }
|
||
}
|
||
|
||
fn a_to_b(e: &mut MyEnum) {
|
||
if let MyEnum::A { name, x: 0 } = e {
|
||
// this takes out our `name` and put in an empty String instead
|
||
// (note that empty strings don't allocate).
|
||
// Then, construct the new enum variant (which will
|
||
// be assigned to `*e`).
|
||
*e = MyEnum::B { name: mem::take(name) }
|
||
}
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<p>This also works with more variants:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>use std::mem;
|
||
|
||
enum MultiVariateEnum {
|
||
A { name: String },
|
||
B { name: String },
|
||
C,
|
||
D
|
||
}
|
||
|
||
fn swizzle(e: &mut MultiVariateEnum) {
|
||
use MultiVariateEnum::*;
|
||
*e = match e {
|
||
// Ownership rules do not allow taking `name` by value, but we cannot
|
||
// take the value out of a mutable reference, unless we replace it:
|
||
A { name } => B { name: mem::take(name) },
|
||
B { name } => A { name: mem::take(name) },
|
||
C => D,
|
||
D => C
|
||
}
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="motivation-2"><a class="header" href="#motivation-2">Motivation</a></h2>
|
||
<p>When working with enums, we may want to change an enum value in place, perhaps
|
||
to another variant. This is usually done in two phases to keep the borrow
|
||
checker happy. In the first phase, we observe the existing value and look at
|
||
its parts to decide what to do next. In the second phase we may conditionally
|
||
change the value (as in the example above).</p>
|
||
<p>The borrow checker won't allow us to take out <code>name</code> of the enum (because
|
||
<em>something</em> must be there.) We could of course <code>.clone()</code> name and put the clone
|
||
into our <code>MyEnum::B</code>, but that would be an instance of the <a href="idioms/../anti_patterns/borrow_clone.html">Clone to satisfy
|
||
the borrow checker</a> anti-pattern. Anyway, we
|
||
can avoid the extra allocation by changing <code>e</code> with only a mutable borrow.</p>
|
||
<p><code>mem::take</code> lets us swap out the value, replacing it with it's default value,
|
||
and returning the previous value. For <code>String</code>, the default value is an empty
|
||
<code>String</code>, which does not need to allocate. As a result, we get the original
|
||
<code>name</code> <em>as an owned value</em>. We can then wrap this in another enum.</p>
|
||
<p><strong>NOTE:</strong> <code>mem::replace</code> is very similar, but allows us to specify what to
|
||
replace the value with. An equivalent to our <code>mem::take</code> line would be
|
||
<code>mem::replace(name, String::new())</code>.</p>
|
||
<p>Note, however, that if we are using an <code>Option</code> and want to replace its
|
||
value with a <code>None</code>, <code>Option</code>’s <code>take()</code> method provides a shorter and
|
||
more idiomatic alternative.</p>
|
||
<h2 id="advantages-3"><a class="header" href="#advantages-3">Advantages</a></h2>
|
||
<p>Look ma, no allocation! Also you may feel like Indiana Jones while doing it.</p>
|
||
<h2 id="disadvantages-3"><a class="header" href="#disadvantages-3">Disadvantages</a></h2>
|
||
<p>This gets a bit wordy. Getting it wrong repeatedly will make you hate the
|
||
borrow checker. The compiler may fail to optimize away the double store,
|
||
resulting in reduced performance as opposed to what you'd do in unsafe
|
||
languages.</p>
|
||
<p>Furthermore, the type you are taking needs to implement the <a href="idioms/./default.html"><code>Default</code>
|
||
trait</a>. However, if the type you're working with doesn't
|
||
implement this, you can instead use <code>mem::replace</code>.</p>
|
||
<h2 id="discussion-2"><a class="header" href="#discussion-2">Discussion</a></h2>
|
||
<p>This pattern is only of interest in Rust. In GC'd languages, you'd take the
|
||
reference to the value by default (and the GC would keep track of refs), and in
|
||
other low-level languages like C you'd simply alias the pointer and fix things
|
||
later.</p>
|
||
<p>However, in Rust, we have to do a little more work to do this. An owned value
|
||
may only have one owner, so to take it out, we need to put something back in –
|
||
like Indiana Jones, replacing the artifact with a bag of sand.</p>
|
||
<h2 id="see-also-5"><a class="header" href="#see-also-5">See also</a></h2>
|
||
<p>This gets rid of the <a href="idioms/../anti_patterns/borrow_clone.html">Clone to satisfy the borrow checker</a>
|
||
anti-pattern in a specific case.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="on-stack-dynamic-dispatch"><a class="header" href="#on-stack-dynamic-dispatch">On-Stack Dynamic Dispatch</a></h1>
|
||
<h2 id="description-7"><a class="header" href="#description-7">Description</a></h2>
|
||
<p>We can dynamically dispatch over multiple values, however, to do so, we need
|
||
to declare multiple variables to bind differently-typed objects. To extend the
|
||
lifetime as necessary, we can use deferred conditional initialization, as seen
|
||
below:</p>
|
||
<h2 id="example-6"><a class="header" href="#example-6">Example</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">use std::io;
|
||
use std::fs;
|
||
|
||
<span class="boring">fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||
</span><span class="boring">let arg = "-";
|
||
</span>
|
||
// These must live longer than `readable`, and thus are declared first:
|
||
let (mut stdin_read, mut file_read);
|
||
|
||
// We need to ascribe the type to get dynamic dispatch.
|
||
let readable: &mut dyn io::Read = if arg == "-" {
|
||
stdin_read = io::stdin();
|
||
&mut stdin_read
|
||
} else {
|
||
file_read = fs::File::open(arg)?;
|
||
&mut file_read
|
||
};
|
||
|
||
// Read from `readable` here.
|
||
|
||
<span class="boring">Ok(())
|
||
</span><span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="motivation-3"><a class="header" href="#motivation-3">Motivation</a></h2>
|
||
<p>Rust monomorphises code by default. This means a copy of the code will be
|
||
generated for each type it is used with and optimized independently. While this
|
||
allows for very fast code on the hot path, it also bloats the code in places
|
||
where performance is not of the essence, thus costing compile time and cache
|
||
usage.</p>
|
||
<p>Luckily, Rust allows us to use dynamic dispatch, but we have to explicitly ask
|
||
for it.</p>
|
||
<h2 id="advantages-4"><a class="header" href="#advantages-4">Advantages</a></h2>
|
||
<p>We do not need to allocate anything on the heap. Neither do we need to
|
||
initialize something we won't use later, nor do we need to monomorphize the
|
||
whole code that follows to work with both <code>File</code> or <code>Stdin</code>.</p>
|
||
<h2 id="disadvantages-4"><a class="header" href="#disadvantages-4">Disadvantages</a></h2>
|
||
<p>The code needs more moving parts than the <code>Box</code>-based version:</p>
|
||
<pre><code class="language-rust ignore">// We still need to ascribe the type for dynamic dispatch.
|
||
let readable: Box<dyn io::Read> = if arg == "-" {
|
||
Box::new(io::stdin())
|
||
} else {
|
||
Box::new(fs::File::open(arg)?)
|
||
};
|
||
// Read from `readable` here.
|
||
</code></pre>
|
||
<h2 id="discussion-3"><a class="header" href="#discussion-3">Discussion</a></h2>
|
||
<p>Rust newcomers will usually learn that Rust requires all variables to be
|
||
initialized <em>before use</em>, so it's easy to overlook the fact that <em>unused</em>
|
||
variables may well be uninitialized. Rust works quite hard to ensure that this
|
||
works out fine and only the initialized values are dropped at the end of their
|
||
scope.</p>
|
||
<p>The example meets all the constraints Rust places on us:</p>
|
||
<ul>
|
||
<li>All variables are initialized before using (in this case borrowing) them</li>
|
||
<li>Each variable only holds values of a single type. In our example, <code>stdin</code> is
|
||
of type <code>Stdin</code>, <code>file</code> is of type <code>File</code> and <code>readable</code> is of type <code>&mut dyn Read</code></li>
|
||
<li>Each borrowed value outlives all the references borrowed from it</li>
|
||
</ul>
|
||
<h2 id="see-also-6"><a class="header" href="#see-also-6">See also</a></h2>
|
||
<ul>
|
||
<li><a href="idioms/dtor-finally.html">Finalisation in destructors</a> and
|
||
<a href="idioms/../patterns/behavioural/RAII.html">RAII guards</a> can benefit from tight control over
|
||
lifetimes.</li>
|
||
<li>For conditionally filled <code>Option<&T></code>s of (mutable) references, one can
|
||
initialize an <code>Option<T></code> directly and use its <a href="https://doc.rust-lang.org/std/option/enum.Option.html#method.as_ref"><code>.as_ref()</code></a> method to get an
|
||
optional reference.</li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="ffi-idioms"><a class="header" href="#ffi-idioms">FFI Idioms</a></h1>
|
||
<p>Writing FFI code is an entire course in itself.
|
||
However, there are several idioms here that can act as pointers, and avoid
|
||
traps for inexperienced users of <code>unsafe</code> Rust.</p>
|
||
<p>This section contains idioms that may be useful when doing FFI.</p>
|
||
<ol>
|
||
<li>
|
||
<p><a href="idioms/ffi/./errors.html">Idiomatic Errors</a> - Error handling with integer codes and
|
||
sentinel return values (such as <code>NULL</code> pointers)</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="idioms/ffi/./accepting-strings.html">Accepting Strings</a> with minimal unsafe code</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="idioms/ffi/./passing-strings.html">Passing Strings</a> to FFI functions</p>
|
||
</li>
|
||
</ol>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="error-handling-in-ffi"><a class="header" href="#error-handling-in-ffi">Error Handling in FFI</a></h1>
|
||
<h2 id="description-8"><a class="header" href="#description-8">Description</a></h2>
|
||
<p>In foreign languages like C, errors are represented by return codes.
|
||
However, Rust's type system allows much more rich error information to be
|
||
captured a propogated through a full type.</p>
|
||
<p>This best practice shows different kinds of error codes, and how to expose them
|
||
in a usable way:</p>
|
||
<ol>
|
||
<li>Flat Enums should be converted to integers and returned as codes.</li>
|
||
<li>Structured Enums should be converted to an integer code with a string error
|
||
message for detail.</li>
|
||
<li>Custom Error Types should become "transparent", with a C representation.</li>
|
||
</ol>
|
||
<h2 id="code-example"><a class="header" href="#code-example">Code Example</a></h2>
|
||
<h3 id="flat-enums"><a class="header" href="#flat-enums">Flat Enums</a></h3>
|
||
<pre><code class="language-rust ignore">enum DatabaseError {
|
||
IsReadOnly = 1, // user attempted a write operation
|
||
IOError = 2, // user should read the C errno() for what it was
|
||
FileCorrupted = 3, // user should run a repair tool to recover it
|
||
}
|
||
|
||
impl From<DatabaseError> for libc::c_int {
|
||
fn from(e: DatabaseError) -> libc::c_int {
|
||
(e as i8).into()
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h3 id="structured-enums"><a class="header" href="#structured-enums">Structured Enums</a></h3>
|
||
<pre><code class="language-rust ignore">pub mod errors {
|
||
enum DatabaseError {
|
||
IsReadOnly,
|
||
IOError(std::io::Error),
|
||
FileCorrupted(String), // message describing the issue
|
||
}
|
||
|
||
impl From<DatabaseError> for libc::c_int {
|
||
fn from(e: DatabaseError) -> libc::c_int {
|
||
match e {
|
||
DatabaseError::IsReadOnly => 1,
|
||
DatabaseError::IOError(_) => 2,
|
||
DatabaseError::FileCorrupted(_) => 3,
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
pub mod c_api {
|
||
use super::errors::DatabaseError;
|
||
|
||
#[no_mangle]
|
||
pub extern "C" fn db_error_description(
|
||
e: *const DatabaseError
|
||
) -> *mut libc::c_char {
|
||
|
||
let error: &DatabaseError = unsafe {
|
||
// SAFETY: pointer lifetime is greater than the current stack frame
|
||
&*e
|
||
};
|
||
|
||
let error_str: String = match error {
|
||
DatabaseError::IsReadOnly => {
|
||
format!("cannot write to read-only database");
|
||
}
|
||
DatabaseError::IOError(e) => {
|
||
format!("I/O Error: {}", e);
|
||
}
|
||
DatabaseError::FileCorrupted(s) => {
|
||
format!("File corrupted, run repair: {}", &s);
|
||
}
|
||
};
|
||
|
||
let c_error = unsafe {
|
||
// SAFETY: copying error_str to an allocated buffer with a NUL
|
||
// character at the end
|
||
let mut malloc: *mut u8 = libc::malloc(error_str.len() + 1) as *mut _;
|
||
|
||
if malloc.is_null() {
|
||
return std::ptr::null_mut();
|
||
}
|
||
|
||
let src = error_str.as_bytes().as_ptr();
|
||
|
||
std::ptr::copy_nonoverlapping(src, malloc, error_str.len());
|
||
|
||
std::ptr::write(malloc.add(error_str.len()), 0);
|
||
|
||
malloc as *mut libc::c_char
|
||
};
|
||
|
||
c_error
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h3 id="custom-error-types"><a class="header" href="#custom-error-types">Custom Error Types</a></h3>
|
||
<pre><code class="language-rust ignore">struct ParseError {
|
||
expected: char,
|
||
line: u32,
|
||
ch: u16
|
||
}
|
||
|
||
impl ParseError { /* ... */ }
|
||
|
||
/* Create a second version which is exposed as a C structure */
|
||
#[repr(C)]
|
||
pub struct parse_error {
|
||
pub expected: libc::c_char,
|
||
pub line: u32,
|
||
pub ch: u16
|
||
}
|
||
|
||
impl From<ParseError> for parse_error {
|
||
fn from(e: ParseError) -> parse_error {
|
||
let ParseError { expected, line, ch } = e;
|
||
parse_error { expected, line, ch }
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h2 id="advantages-5"><a class="header" href="#advantages-5">Advantages</a></h2>
|
||
<p>This ensures that the foreign language has clear access to error information
|
||
while not compromising the Rust code's API at all.</p>
|
||
<h2 id="disadvantages-5"><a class="header" href="#disadvantages-5">Disadvantages</a></h2>
|
||
<p>It's a lot of typing, and some types may not be able to be converted easily
|
||
to C.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="accepting-strings"><a class="header" href="#accepting-strings">Accepting Strings</a></h1>
|
||
<h2 id="description-9"><a class="header" href="#description-9">Description</a></h2>
|
||
<p>When accepting strings via FFI through pointers, there are two principles that
|
||
should be followed:</p>
|
||
<ol>
|
||
<li>Keep foreign strings "borrowed", rather than copying them directly.</li>
|
||
<li>Minimize the amount of complexity and <code>unsafe</code> code involved in converting
|
||
from a C-style string to native Rust strings.</li>
|
||
</ol>
|
||
<h2 id="motivation-4"><a class="header" href="#motivation-4">Motivation</a></h2>
|
||
<p>The strings used in C have different behaviours to those used in Rust, namely:</p>
|
||
<ul>
|
||
<li>C strings are null-terminated while Rust strings store their length</li>
|
||
<li>C strings can contain any arbitrary non-zero byte while Rust strings must be
|
||
UTF-8</li>
|
||
<li>C strings are accessed and manipulated using <code>unsafe</code> pointer operations
|
||
while interactions with Rust strings go through safe methods</li>
|
||
</ul>
|
||
<p>The Rust standard library comes with C equivalents of Rust's <code>String</code> and <code>&str</code>
|
||
called <code>CString</code> and <code>&CStr</code>, that allow us to avoid a lot of the complexity
|
||
and <code>unsafe</code> code involved in converting between C strings and Rust strings.</p>
|
||
<p>The <code>&CStr</code> type also allows us to work with borrowed data, meaning passing
|
||
strings between Rust and C is a zero-cost operation.</p>
|
||
<h2 id="code-example-1"><a class="header" href="#code-example-1">Code Example</a></h2>
|
||
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
||
|
||
// other module content
|
||
|
||
/// Log a message at the specified level.
|
||
///
|
||
/// # Safety
|
||
///
|
||
/// It is the caller's guarantee to ensure `msg`:
|
||
///
|
||
/// - is not a null pointer
|
||
/// - points to valid, initialized data
|
||
/// - points to memory ending in a null byte
|
||
/// - won't be mutated for the duration of this function call
|
||
#[no_mangle]
|
||
pub unsafe extern "C" fn mylib_log(
|
||
msg: *const libc::c_char,
|
||
level: libc::c_int
|
||
) {
|
||
let level: crate::LogLevel = match level { /* ... */ };
|
||
|
||
// SAFETY: The caller has already guaranteed this is okay (see the
|
||
// `# Safety` section of the doc-comment).
|
||
let msg_str: &str = match std::ffi::CStr::from_ptr(msg).to_str() {
|
||
Ok(s) => s,
|
||
Err(e) => {
|
||
crate::log_error("FFI string conversion failed");
|
||
return;
|
||
}
|
||
};
|
||
|
||
crate::log(msg_str, level);
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h2 id="advantages-6"><a class="header" href="#advantages-6">Advantages</a></h2>
|
||
<p>The example is is written to ensure that:</p>
|
||
<ol>
|
||
<li>The <code>unsafe</code> block is as small as possible.</li>
|
||
<li>The pointer with an "untracked" lifetime becomes a "tracked" shared
|
||
reference</li>
|
||
</ol>
|
||
<p>Consider an alternative, where the string is actually copied:</p>
|
||
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
||
|
||
// other module content
|
||
|
||
pub extern "C" fn mylib_log(msg: *const libc::c_char, level: libc::c_int) {
|
||
// DO NOT USE THIS CODE.
|
||
// IT IS UGLY, VERBOSE, AND CONTAINS A SUBTLE BUG.
|
||
|
||
let level: crate::LogLevel = match level { /* ... */ };
|
||
|
||
let msg_len = unsafe { /* SAFETY: strlen is what it is, I guess? */
|
||
libc::strlen(msg)
|
||
};
|
||
|
||
let mut msg_data = Vec::with_capacity(msg_len + 1);
|
||
|
||
let msg_cstr: std::ffi::CString = unsafe {
|
||
// SAFETY: copying from a foreign pointer expected to live
|
||
// for the entire stack frame into owned memory
|
||
std::ptr::copy_nonoverlapping(msg, msg_data.as_mut(), msg_len);
|
||
|
||
msg_data.set_len(msg_len + 1);
|
||
|
||
std::ffi::CString::from_vec_with_nul(msg_data).unwrap()
|
||
}
|
||
|
||
let msg_str: String = unsafe {
|
||
match msg_cstr.into_string() {
|
||
Ok(s) => s,
|
||
Err(e) => {
|
||
crate::log_error("FFI string conversion failed");
|
||
return;
|
||
}
|
||
}
|
||
};
|
||
|
||
crate::log(&msg_str, level);
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>This code in inferior to the original in two respects:</p>
|
||
<ol>
|
||
<li>There is much more <code>unsafe</code> code, and more importantly, more invariants it
|
||
must uphold.</li>
|
||
<li>Due to the extensive arithmetic required, there is a bug in this version
|
||
that cases Rust <code>undefined behaviour</code>.</li>
|
||
</ol>
|
||
<p>The bug here is a simple mistake in pointer arithmetic: the string was copied,
|
||
all <code>msg_len</code> bytes of it. However, the <code>NUL</code> terminator at the end was not.</p>
|
||
<p>The Vector then had its size <em>set</em> to the length of the <em>zero padded string</em> --
|
||
rather than <em>resized</em> to it, which could have added a zero at the end.
|
||
As a result, the last byte in the Vector is uninitialized memory.
|
||
When the <code>CString</code> is created at the bottom of the block, its read of the
|
||
Vector will cause <code>undefined behaviour</code>!</p>
|
||
<p>Like many such issues, this would be difficult issue to track down.
|
||
Sometimes it would panic because the string was not <code>UTF-8</code>, sometimes it would
|
||
put a weird character at the end of the string, sometimes it would just
|
||
completely crash.</p>
|
||
<h2 id="disadvantages-6"><a class="header" href="#disadvantages-6">Disadvantages</a></h2>
|
||
<p>None?</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="passing-strings"><a class="header" href="#passing-strings">Passing Strings</a></h1>
|
||
<h2 id="description-10"><a class="header" href="#description-10">Description</a></h2>
|
||
<p>When passing strings to FFI functions, there are four principles that should be
|
||
followed:</p>
|
||
<ol>
|
||
<li>Make the lifetime of owned strings as long as possible.</li>
|
||
<li>Minimize <code>unsafe</code> code during the conversion.</li>
|
||
<li>If the C code can modify the string data, use <code>Vec</code> instead of <code>CString</code>.</li>
|
||
<li>Unless the Foreign Function API requires it, the ownership of the string
|
||
should not transfer to the callee.</li>
|
||
</ol>
|
||
<h2 id="motivation-5"><a class="header" href="#motivation-5">Motivation</a></h2>
|
||
<p>Rust has built-in support for C-style strings with its <code>CString</code> and <code>CStr</code>
|
||
types. However, there are different approaches one can take with strings that
|
||
are being sent to a foreign function call from a Rust function.</p>
|
||
<p>The best practice is simple: use <code>CString</code> in such a way as to minimize
|
||
<code>unsafe</code> code. However, a secondary caveat is that
|
||
<em>the object must live long enough</em>, meaning the lifetime should be maximized.
|
||
In addition, the documentation explains that "round-tripping" a <code>CString</code> after
|
||
modification is UB, so additional work is necessary in that case.</p>
|
||
<h2 id="code-example-2"><a class="header" href="#code-example-2">Code Example</a></h2>
|
||
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
||
|
||
// other module content
|
||
|
||
extern "C" {
|
||
fn seterr(message: *const libc::c_char);
|
||
fn geterr(buffer: *mut libc::c_char, size: libc::c_int) -> libc::c_int;
|
||
}
|
||
|
||
fn report_error_to_ffi<S: Into<String>>(
|
||
err: S
|
||
) -> Result<(), std::ffi::NulError>{
|
||
let c_err = std::ffi::CString::new(err.into())?;
|
||
|
||
unsafe {
|
||
// SAFETY: calling an FFI whose documentation says the pointer is
|
||
// const, so no modification should occur
|
||
seterr(c_err.as_ptr());
|
||
}
|
||
|
||
Ok(())
|
||
// The lifetime of c_err continues until here
|
||
}
|
||
|
||
fn get_error_from_ffi() -> Result<String, std::ffi::IntoStringError> {
|
||
let mut buffer = vec![0u8; 1024];
|
||
unsafe {
|
||
// SAFETY: calling an FFI whose documentation implies
|
||
// that the input need only live as long as the call
|
||
let written: usize = geterr(buffer.as_mut_ptr(), 1023).into();
|
||
|
||
buffer.truncate(written + 1);
|
||
}
|
||
|
||
std::ffi::CString::new(buffer).unwrap().into_string()
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h2 id="advantages-7"><a class="header" href="#advantages-7">Advantages</a></h2>
|
||
<p>The example is written in a way to ensure that:</p>
|
||
<ol>
|
||
<li>The <code>unsafe</code> block is as small as possible.</li>
|
||
<li>The <code>CString</code> lives long enough.</li>
|
||
<li>Errors with typecasts are always propagated when possible.</li>
|
||
</ol>
|
||
<p>A common mistake (so common it's in the documentation) is to not use the
|
||
variable in the first block:</p>
|
||
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
||
|
||
// other module content
|
||
|
||
fn report_error<S: Into<String>>(err: S) -> Result<(), std::ffi::NulError> {
|
||
unsafe {
|
||
// SAFETY: whoops, this contains a dangling pointer!
|
||
seterr(std::ffi::CString::new(err.into())?.as_ptr());
|
||
}
|
||
Ok(())
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>This code will result in a dangling pointer, because the lifetime of the
|
||
<code>CString</code> is not extended by the pointer creation, unlike if a reference were
|
||
created.</p>
|
||
<p>Another issue frequently raised is that the initialization of a 1k vector of
|
||
zeroes is "slow". However, recent versions of Rust actually optimize that
|
||
particular macro to a call to <code>zmalloc</code>, meaning it is as fast as the operating
|
||
system's ability to return zeroed memory (which is quite fast).</p>
|
||
<h2 id="disadvantages-7"><a class="header" href="#disadvantages-7">Disadvantages</a></h2>
|
||
<p>None?</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="iterating-over-an-option"><a class="header" href="#iterating-over-an-option">Iterating over an <code>Option</code></a></h1>
|
||
<h2 id="description-11"><a class="header" href="#description-11">Description</a></h2>
|
||
<p><code>Option</code> can be viewed as a container that contains either zero or one
|
||
element. In particular, it implements the <code>IntoIterator</code> trait, and as such
|
||
can be used with generic code that needs such a type.</p>
|
||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
||
<p>Since <code>Option</code> implements <code>IntoIterator</code>, it can be used as an argument to
|
||
<a href="https://doc.rust-lang.org/std/iter/trait.Extend.html#tymethod.extend"><code>.extend()</code></a>:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>let turing = Some("Turing");
|
||
let mut logicians = vec!["Curry", "Kleene", "Markov"];
|
||
|
||
logicians.extend(turing);
|
||
|
||
// equivalent to
|
||
if let Some(turing_inner) = turing {
|
||
logicians.push(turing_inner);
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<p>If you need to tack an <code>Option</code> to the end of an existing iterator, you can
|
||
pass it to <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.chain"><code>.chain()</code></a>:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>let turing = Some("Turing");
|
||
let logicians = vec!["Curry", "Kleene", "Markov"];
|
||
|
||
for logician in logicians.iter().chain(turing.iter()) {
|
||
println!("{} is a logician", logician);
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<p>Note that if the <code>Option</code> is always <code>Some</code>, then it is more idiomatic to use
|
||
<a href="https://doc.rust-lang.org/std/iter/fn.once.html"><code>std::iter::once</code></a> on the
|
||
element instead.</p>
|
||
<p>Also, since <code>Option</code> implements <code>IntoIterator</code>, it's possible to iterate over
|
||
it using a <code>for</code> loop. This is equivalent to matching it with <code>if let Some(..)</code>,
|
||
and in most cases you should prefer the latter.</p>
|
||
<h2 id="see-also-7"><a class="header" href="#see-also-7">See also</a></h2>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://doc.rust-lang.org/std/iter/fn.once.html"><code>std::iter::once</code></a> is an
|
||
iterator which yields exactly one element. It's a more readable alternative to
|
||
<code>Some(foo).into_iter()</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map"><code>Iterator::filter_map</code></a>
|
||
is a version of <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map"><code>Iterator::flat_map</code></a>,
|
||
specialized to mapping functions which return <code>Option</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>The <a href="https://crates.io/crates/ref_slice"><code>ref_slice</code></a> crate provides functions
|
||
for converting an <code>Option</code> to a zero- or one-element slice.</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://doc.rust-lang.org/std/option/enum.Option.html">Documentation for <code>Option<T></code></a></p>
|
||
</li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="pass-variables-to-closure"><a class="header" href="#pass-variables-to-closure">Pass variables to closure</a></h1>
|
||
<h2 id="description-12"><a class="header" href="#description-12">Description</a></h2>
|
||
<p>By default, closures capture their environment by borrowing. Or you can use
|
||
<code>move</code>-closure to move whole environment. However, often you want to move just
|
||
some variables to closure, give it copy of some data, pass it by reference, or
|
||
perform some other transformation.</p>
|
||
<p>Use variable rebinding in separate scope for that.</p>
|
||
<h2 id="example-7"><a class="header" href="#example-7">Example</a></h2>
|
||
<p>Use</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>use std::rc::Rc;
|
||
|
||
let num1 = Rc::new(1);
|
||
let num2 = Rc::new(2);
|
||
let num3 = Rc::new(3);
|
||
let closure = {
|
||
// `num1` is moved
|
||
let num2 = num2.clone(); // `num2` is cloned
|
||
let num3 = num3.as_ref(); // `num3` is borrowed
|
||
move || {
|
||
*num1 + *num2 + *num3;
|
||
}
|
||
};
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<p>instead of</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>use std::rc::Rc;
|
||
|
||
let num1 = Rc::new(1);
|
||
let num2 = Rc::new(2);
|
||
let num3 = Rc::new(3);
|
||
|
||
let num2_cloned = num2.clone();
|
||
let num3_borrowed = num3.as_ref();
|
||
let closure = move || {
|
||
*num1 + *num2_cloned + *num3_borrowed;
|
||
};
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="advantages-8"><a class="header" href="#advantages-8">Advantages</a></h2>
|
||
<p>Copied data are grouped together with closure definition, so their purpose is
|
||
more clear, and they will be dropped immediately even if they are not consumed
|
||
by closure.</p>
|
||
<p>Closure uses same variable names as surrounding code whether data are copied or
|
||
moved.</p>
|
||
<h2 id="disadvantages-8"><a class="header" href="#disadvantages-8">Disadvantages</a></h2>
|
||
<p>Additional indentation of closure body.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="non_exhaustive-and-private-fields-for-extensibility"><a class="header" href="#non_exhaustive-and-private-fields-for-extensibility"><code>#[non_exhaustive]</code> and private fields for extensibility</a></h1>
|
||
<h2 id="description-13"><a class="header" href="#description-13">Description</a></h2>
|
||
<p>A small set of scenarios exist where a library author may want to add public
|
||
fields to a public struct or new variants to an enum without breaking backwards
|
||
compatibility.</p>
|
||
<p>Rust offers two solutions to this problem:</p>
|
||
<ul>
|
||
<li>
|
||
<p>Use <code>#[non_exhaustive]</code> on <code>struct</code>s, <code>enum</code>s, and <code>enum</code> variants.
|
||
For extensive documentation on all the places where <code>#[non_exhaustive]</code> can be
|
||
used, see <a href="https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute">the docs</a>.</p>
|
||
</li>
|
||
<li>
|
||
<p>You may add a private field to a struct to prevent it from being directly
|
||
instantiated or matched against (see Alternative)</p>
|
||
</li>
|
||
</ul>
|
||
<h2 id="example-8"><a class="header" href="#example-8">Example</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>mod a {
|
||
// Public struct.
|
||
#[non_exhaustive]
|
||
pub struct S {
|
||
pub foo: i32,
|
||
}
|
||
|
||
#[non_exhaustive]
|
||
pub enum AdmitMoreVariants {
|
||
VariantA,
|
||
VariantB,
|
||
#[non_exhaustive]
|
||
VariantC { a: String }
|
||
}
|
||
}
|
||
|
||
fn print_matched_variants(s: a::S) {
|
||
// Because S is `#[non_exhaustive]`, it cannot be named here and
|
||
// we must use `..` in the pattern.
|
||
let a::S { foo: _, ..} = s;
|
||
|
||
let some_enum = a::AdmitMoreVariants::VariantA;
|
||
match some_enum {
|
||
a::AdmitMoreVariants::VariantA => println!("it's an A"),
|
||
a::AdmitMoreVariants::VariantB => println!("it's a b"),
|
||
|
||
// .. required because this variant is non-exhaustive as well
|
||
a::AdmitMoreVariants::VariantC { a, .. } => println!("it's a c"),
|
||
|
||
// The wildcard match is required because more variants may be
|
||
// added in the future
|
||
_ => println!("it's a new variant")
|
||
}
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="alternative-private-fields-for-structs"><a class="header" href="#alternative-private-fields-for-structs">Alternative: <code>Private fields</code> for structs</a></h2>
|
||
<p><code>#[non_exhaustive]</code> only works across crate boundaries.
|
||
Within a crate, the private field method may be used.</p>
|
||
<p>Adding a field to a struct is a mostly backwards compatible change.
|
||
However, if a client uses a pattern to deconstruct a struct instance, they
|
||
might name all the fields in the struct and adding a new one would break that
|
||
pattern.
|
||
The client could name some fields and use <code>..</code> in the pattern, in which case adding
|
||
another field is backwards compatible.
|
||
Making at least one of the struct's fields private forces clients to use the latter
|
||
form of patterns, ensuring that the struct is future-proof.</p>
|
||
<p>The downside of this approach is that you might need to add an otherwise unneeded
|
||
field to the struct.
|
||
You can use the <code>()</code> type so that there is no runtime overhead and prepend <code>_</code> to
|
||
the field name to avoid the unused field warning.</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>pub struct S {
|
||
pub a: i32,
|
||
// Because `b` is private, you cannot match on `S` without using `..` and `S`
|
||
// cannot be directly instantiated or matched against
|
||
_b: ()
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="discussion-4"><a class="header" href="#discussion-4">Discussion</a></h2>
|
||
<p>On <code>struct</code>s, <code>#[non_exhaustive]</code> allows adding additional fields in a backwards
|
||
compatible way.
|
||
It will also prevent clients from using the struct constructor, even if all the
|
||
fields are public.
|
||
This may be helpful, but it's worth considering if you <em>want</em> an additional field
|
||
to be found by clients as a compiler error rather than something that may be silently
|
||
undiscovered.</p>
|
||
<p><code>#[non_exhaustive]</code> can be applied to enum variants as well.
|
||
A <code>#[non_exhaustive]</code> variant behaves in the same way as a <code>#[non_exhaustive]</code> struct.</p>
|
||
<p>Use this deliberately and with caution: incrementing the major version when adding
|
||
fields or variants is often a better option.
|
||
<code>#[non_exhaustive]</code> may be appropriate in scenarios where you're modeling an external
|
||
resource that may change out-of-sync with your library, but is not a general purpose
|
||
tool.</p>
|
||
<h3 id="disadvantages-9"><a class="header" href="#disadvantages-9">Disadvantages</a></h3>
|
||
<p><code>#[non_exhaustive]</code> can make your code much less ergonomic to use, especially when
|
||
forced to handle unknown enum variants.
|
||
It should only be used when these sorts of evolutions are required <strong>without</strong>
|
||
incrementing the major version.</p>
|
||
<p>When <code>#[non_exhaustive]</code> is applied to <code>enum</code>s, it forces clients to handle a
|
||
wildcard variant.
|
||
If there is no sensible action to take in this case, this may lead to awkward
|
||
code and code paths that are only executed in extremely rare circumstances.
|
||
If a client decides to <code>panic!()</code> in this scenario, it may have been better to
|
||
expose this error at compile time.
|
||
In fact, <code>#[non_exhaustive]</code> forces clients to handle the "Something else" case;
|
||
there is rarely a sensible action to take in this scenario.</p>
|
||
<h2 id="see-also-8"><a class="header" href="#see-also-8">See also</a></h2>
|
||
<ul>
|
||
<li><a href="https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md">RFC introducing #[non_exhaustive] attribute for enums and structs</a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="easy-doc-initialization"><a class="header" href="#easy-doc-initialization">Easy doc initialization</a></h1>
|
||
<h2 id="description-14"><a class="header" href="#description-14">Description</a></h2>
|
||
<p>If a struct takes significant effort to initialize, when writing docs, it can be
|
||
quicker to wrap your example with a helper function which takes the struct as an
|
||
argument.</p>
|
||
<h2 id="motivation-6"><a class="header" href="#motivation-6">Motivation</a></h2>
|
||
<p>Sometimes there is a struct with multiple or complicated parameters and several
|
||
methods. Each of these methods should have examples.</p>
|
||
<p>For example:</p>
|
||
<pre><code class="language-rust ignore">struct Connection {
|
||
name: String,
|
||
stream: TcpStream,
|
||
}
|
||
|
||
impl Connection {
|
||
/// Sends a request over the connection.
|
||
///
|
||
/// # Example
|
||
/// ```no_run
|
||
/// # // Boilerplate are required to get an example working.
|
||
/// # let stream = TcpStream::connect("127.0.0.1:34254");
|
||
/// # let connection = Connection { name: "foo".to_owned(), stream };
|
||
/// # let request = Request::new("RequestId", RequestType::Get, "payload");
|
||
/// let response = connection.send_request(request);
|
||
/// assert!(response.is_ok());
|
||
/// ```
|
||
fn send_request(&self, request: Request) -> Result<Status, SendErr> {
|
||
// ...
|
||
}
|
||
|
||
/// Oh no, all that boilerplate needs to be repeated here!
|
||
fn check_status(&self) -> Status {
|
||
// ...
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h2 id="example-9"><a class="header" href="#example-9">Example</a></h2>
|
||
<p>Instead of typing all of this boilerplate to create an <code>Connection</code> and
|
||
<code>Request</code> it is easier to just create a wrapping helper function which takes
|
||
them as arguments:</p>
|
||
<pre><code class="language-rust ignore">struct Connection {
|
||
name: String,
|
||
stream: TcpStream,
|
||
}
|
||
|
||
impl Connection {
|
||
/// Sends a request over the connection.
|
||
///
|
||
/// # Example
|
||
/// ```
|
||
/// # fn call_send(connection: Connection, request: Request) {
|
||
/// let response = connection.send_request(request);
|
||
/// assert!(response.is_ok());
|
||
/// # }
|
||
/// ```
|
||
fn send_request(&self, request: Request) {
|
||
// ...
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p><strong>Note</strong> in the above example the line <code>assert!(response.is_ok());</code> will not
|
||
actually run while testing because it is inside a function which is never
|
||
invoked.</p>
|
||
<h2 id="advantages-9"><a class="header" href="#advantages-9">Advantages</a></h2>
|
||
<p>This is much more concise and avoids repetitive code in examples.</p>
|
||
<h2 id="disadvantages-10"><a class="header" href="#disadvantages-10">Disadvantages</a></h2>
|
||
<p>As example is in a function, the code will not be tested. Though it will still be
|
||
checked to make sure it compiles when running a <code>cargo test</code>. So this pattern is
|
||
most useful when you need <code>no_run</code>. With this, you do not need to add <code>no_run</code>.</p>
|
||
<h2 id="discussion-5"><a class="header" href="#discussion-5">Discussion</a></h2>
|
||
<p>If assertions are not required this pattern works well.</p>
|
||
<p>If they are, an alternative can be to create a public method to create a helper
|
||
instance which is annotated with <code>#[doc(hidden)]</code> (so that users won't see it).
|
||
Then this method can be called inside of rustdoc because it is part of the
|
||
crate's public API.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="temporary-mutability"><a class="header" href="#temporary-mutability">Temporary mutability</a></h1>
|
||
<h2 id="description-15"><a class="header" href="#description-15">Description</a></h2>
|
||
<p>Often it is necessary to prepare and process some data, but after that data are
|
||
only inspected and never modified. The intention can be made explicit by redefining
|
||
the mutable variable as immutable.</p>
|
||
<p>It can be done either by processing data within nested block or by redefining
|
||
variable.</p>
|
||
<h2 id="example-10"><a class="header" href="#example-10">Example</a></h2>
|
||
<p>Say, vector must be sorted before usage.</p>
|
||
<p>Using nested block:</p>
|
||
<pre><code class="language-rust ignore">let data = {
|
||
let mut data = get_vec();
|
||
data.sort();
|
||
data
|
||
};
|
||
|
||
// Here `data` is immutable.
|
||
</code></pre>
|
||
<p>Using variable rebinding:</p>
|
||
<pre><code class="language-rust ignore">let mut data = get_vec();
|
||
data.sort();
|
||
let data = data;
|
||
|
||
// Here `data` is immutable.
|
||
</code></pre>
|
||
<h2 id="advantages-10"><a class="header" href="#advantages-10">Advantages</a></h2>
|
||
<p>Compiler ensures that you don't accidentally mutate data after some point.</p>
|
||
<h2 id="disadvantages-11"><a class="header" href="#disadvantages-11">Disadvantages</a></h2>
|
||
<p>Nested block requires additional indentation of block body.
|
||
One more line to return data from block or redefine variable.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="design-patterns-1"><a class="header" href="#design-patterns-1">Design Patterns</a></h1>
|
||
<p><a href="https://en.wikipedia.org/wiki/Software_design_pattern">Design patterns</a> are
|
||
"general reusable solutions to a commonly occurring problem within a given
|
||
context in software design". Design patterns are a great way to describe the
|
||
culture of a programming language. Design patterns are very language-specific -
|
||
what is a pattern in one language may be unnecessary in another due to a
|
||
language feature, or impossible to express due to a missing feature.</p>
|
||
<p>If overused, design patterns can add unnecessary complexity to programs.
|
||
However, they are a great way to share intermediate and advanced level knowledge
|
||
about a programming language.</p>
|
||
<h2 id="design-patterns-in-rust-1"><a class="header" href="#design-patterns-in-rust-1">Design patterns in Rust</a></h2>
|
||
<p>Rust has many unique features. These features give us great benefit by removing
|
||
whole classes of problems. Some of them are also patterns that are <em>unique</em> to Rust.</p>
|
||
<h2 id="yagni"><a class="header" href="#yagni">YAGNI</a></h2>
|
||
<p>If you're not familiar with it, YAGNI is an acronym that stands for
|
||
<code>You Aren't Going to Need It</code>. It's an important software design principle to apply
|
||
as you write code.</p>
|
||
<blockquote>
|
||
<p>The best code I ever wrote was code I never wrote.</p>
|
||
</blockquote>
|
||
<p>If we apply YAGNI to design patterns, we see that the features of Rust allow us to
|
||
throw out many patterns. For instance, there is no need for the <a href="https://en.wikipedia.org/wiki/Strategy_pattern">strategy pattern</a>
|
||
in Rust because we can just use <a href="https://doc.rust-lang.org/book/traits.html">traits</a>.</p>
|
||
<p>TODO: Maybe include some code to illustrate the traits.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="behavioural-patterns"><a class="header" href="#behavioural-patterns">Behavioural Patterns</a></h1>
|
||
<p>From <a href="https://en.wikipedia.org/wiki/Behavioral_pattern">Wikipedia</a>:</p>
|
||
<blockquote>
|
||
<p>Design patterns that identify common communication patterns among objects.
|
||
By doing so, these patterns increase flexibility in carrying out communication.</p>
|
||
</blockquote>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="command"><a class="header" href="#command">Command</a></h1>
|
||
<h2 id="description-16"><a class="header" href="#description-16">Description</a></h2>
|
||
<p>The basic idea of the Command pattern is to separate out actions into its own
|
||
objects and pass them as parameters.</p>
|
||
<h2 id="motivation-7"><a class="header" href="#motivation-7">Motivation</a></h2>
|
||
<p>Suppose we have a sequence of actions or transactions encapsulated as objects.
|
||
We want these actions or commands to be executed or invoked in some order later
|
||
at different time. These commands may also be triggered as a result of some event.
|
||
For example, when a user pushes a button, or on arrival of a data packet.
|
||
In addition, these commands might be undoable. This may come in useful for
|
||
operations of an editor. We might want to store logs of executed commands so that
|
||
we could reapply the changes later if the system crashes.</p>
|
||
<h2 id="example-11"><a class="header" href="#example-11">Example</a></h2>
|
||
<p>Define two database operations <code>create table</code> and <code>add field</code>. Each of these
|
||
operations is a command which knows how to undo the command, e.g., <code>drop table</code>
|
||
and <code>remove field</code>. When a user invokes a database migration operation then each
|
||
command is executed in the defined order, and when the user invokes the rollback
|
||
operation then the whole set of commands is invoked in reverse order.</p>
|
||
<h2 id="approach-using-trait-objects"><a class="header" href="#approach-using-trait-objects">Approach: Using trait objects</a></h2>
|
||
<p>We define a common trait which encapsulates our command with two operations
|
||
<code>execute</code> and <code>rollback</code>. All command <code>structs</code> must implement this trait.</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">pub trait Migration {
|
||
fn execute(&self) -> &str;
|
||
fn rollback(&self) -> &str;
|
||
}
|
||
|
||
pub struct CreateTable;
|
||
impl Migration for CreateTable {
|
||
fn execute(&self) -> &str {
|
||
"create table"
|
||
}
|
||
fn rollback(&self) -> &str {
|
||
"drop table"
|
||
}
|
||
}
|
||
|
||
pub struct AddField;
|
||
impl Migration for AddField {
|
||
fn execute(&self) -> &str {
|
||
"add field"
|
||
}
|
||
fn rollback(&self) -> &str {
|
||
"remove field"
|
||
}
|
||
}
|
||
|
||
struct Schema {
|
||
commands: Vec<Box<dyn Migration>>,
|
||
}
|
||
|
||
impl Schema {
|
||
fn new() -> Self {
|
||
Self { commands: vec![] }
|
||
}
|
||
|
||
fn add_migration(&mut self, cmd: Box<dyn Migration>) {
|
||
self.commands.push(cmd);
|
||
}
|
||
|
||
fn execute(&self) -> Vec<&str> {
|
||
self.commands.iter().map(|cmd| cmd.execute()).collect()
|
||
}
|
||
fn rollback(&self) -> Vec<&str> {
|
||
self.commands
|
||
.iter()
|
||
.rev() // reverse iterator's direction
|
||
.map(|cmd| cmd.rollback())
|
||
.collect()
|
||
}
|
||
}
|
||
|
||
fn main() {
|
||
let mut schema = Schema::new();
|
||
|
||
let cmd = Box::new(CreateTable);
|
||
schema.add_migration(cmd);
|
||
let cmd = Box::new(AddField);
|
||
schema.add_migration(cmd);
|
||
|
||
assert_eq!(vec!["create table", "add field"], schema.execute());
|
||
assert_eq!(vec!["remove field", "drop table"], schema.rollback());
|
||
}
|
||
</code></pre></pre>
|
||
<h2 id="approach-using-function-pointers"><a class="header" href="#approach-using-function-pointers">Approach: Using function pointers</a></h2>
|
||
<p>We could follow another approach by creating each individual command as
|
||
a different function and store function pointers to invoke these functions later
|
||
at a different time. Since function pointers implement all three traits <code>Fn</code>,
|
||
<code>FnMut</code>, and <code>FnOnce</code> we could as well pass and store closures instead of
|
||
function pointers.</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">type FnPtr = fn() -> String;
|
||
struct Command {
|
||
execute: FnPtr,
|
||
rollback: FnPtr,
|
||
}
|
||
|
||
struct Schema {
|
||
commands: Vec<Command>,
|
||
}
|
||
|
||
impl Schema {
|
||
fn new() -> Self {
|
||
Self { commands: vec![] }
|
||
}
|
||
fn add_migration(&mut self, execute: FnPtr, rollback: FnPtr) {
|
||
self.commands.push(Command { execute, rollback });
|
||
}
|
||
fn execute(&self) -> Vec<String> {
|
||
self.commands.iter().map(|cmd| (cmd.execute)()).collect()
|
||
}
|
||
fn rollback(&self) -> Vec<String> {
|
||
self.commands
|
||
.iter()
|
||
.rev()
|
||
.map(|cmd| (cmd.rollback)())
|
||
.collect()
|
||
}
|
||
}
|
||
|
||
fn add_field() -> String {
|
||
"add field".to_string()
|
||
}
|
||
|
||
fn remove_field() -> String {
|
||
"remove field".to_string()
|
||
}
|
||
|
||
fn main() {
|
||
let mut schema = Schema::new();
|
||
schema.add_migration(|| "create table".to_string(), || "drop table".to_string());
|
||
schema.add_migration(add_field, remove_field);
|
||
assert_eq!(vec!["create table", "add field"], schema.execute());
|
||
assert_eq!(vec!["remove field", "drop table"], schema.rollback());
|
||
}
|
||
</code></pre></pre>
|
||
<h2 id="approach-using-fn-trait-objects"><a class="header" href="#approach-using-fn-trait-objects">Approach: Using <code>Fn</code> trait objects</a></h2>
|
||
<p>Finally, instead of defining a common command trait we could store
|
||
each command implementing the <code>Fn</code> trait separately in vectors.</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">type Migration<'a> = Box<dyn Fn() -> &'a str>;
|
||
|
||
struct Schema<'a> {
|
||
executes: Vec<Migration<'a>>,
|
||
rollbacks: Vec<Migration<'a>>,
|
||
}
|
||
|
||
impl<'a> Schema<'a> {
|
||
fn new() -> Self {
|
||
Self {
|
||
executes: vec![],
|
||
rollbacks: vec![],
|
||
}
|
||
}
|
||
fn add_migration<E, R>(&mut self, execute: E, rollback: R)
|
||
where
|
||
E: Fn() -> &'a str + 'static,
|
||
R: Fn() -> &'a str + 'static,
|
||
{
|
||
self.executes.push(Box::new(execute));
|
||
self.rollbacks.push(Box::new(rollback));
|
||
}
|
||
fn execute(&self) -> Vec<&str> {
|
||
self.executes.iter().map(|cmd| cmd()).collect()
|
||
}
|
||
fn rollback(&self) -> Vec<&str> {
|
||
self.rollbacks.iter().rev().map(|cmd| cmd()).collect()
|
||
}
|
||
}
|
||
|
||
fn add_field() -> &'static str {
|
||
"add field"
|
||
}
|
||
|
||
fn remove_field() -> &'static str {
|
||
"remove field"
|
||
}
|
||
|
||
fn main() {
|
||
let mut schema = Schema::new();
|
||
schema.add_migration(|| "create table", || "drop table");
|
||
schema.add_migration(add_field, remove_field);
|
||
assert_eq!(vec!["create table", "add field"], schema.execute());
|
||
assert_eq!(vec!["remove field", "drop table"], schema.rollback());
|
||
}
|
||
</code></pre></pre>
|
||
<h2 id="discussion-6"><a class="header" href="#discussion-6">Discussion</a></h2>
|
||
<p>If our commands are small and may be defined as functions or passed as a closure
|
||
then using function pointers might be preferable since it does not exploit
|
||
dynamic dispatch. But if our command is a whole struct with a bunch of functions
|
||
and variables defined as seperated module then using trait objects would be
|
||
more suitable. A case of application can be found in <a href="https://actix.rs/"><code>actix</code></a>,
|
||
which uses trait objects when it registers a handler function for routes.
|
||
In case of using <code>Fn</code> trait objects we can create and use commands in the same
|
||
way as we used in case of function pointers.</p>
|
||
<p>As performance, there is always a trade-off between performance and code
|
||
simplicity and organisation. Static dispatch gives faster performance, while
|
||
dynamic dispatch provides flexibility when we structure our application.</p>
|
||
<h2 id="see-also-9"><a class="header" href="#see-also-9">See also</a></h2>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://en.wikipedia.org/wiki/Command_pattern">Command pattern</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://web.archive.org/web/20210223131236/https://chercher.tech/rust/command-design-pattern-rust">Another example for the <code>command</code> pattern</a></p>
|
||
</li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="interpreter"><a class="header" href="#interpreter">Interpreter</a></h1>
|
||
<h2 id="description-17"><a class="header" href="#description-17">Description</a></h2>
|
||
<p>If a problem occurs very often and requires long and repetitive steps to solve
|
||
it, then the problem instances might be expressed in a simple language and an
|
||
interpreter object could solve it by interpreting the sentences written in this
|
||
simple language.</p>
|
||
<p>Basically, for any kind of problems we define:</p>
|
||
<ul>
|
||
<li>a <a href="https://en.wikipedia.org/wiki/Domain-specific_language">domain specific language</a>,</li>
|
||
<li>a grammar for this language,</li>
|
||
<li>an interpreter that solves the problem instances.</li>
|
||
</ul>
|
||
<h2 id="motivation-8"><a class="header" href="#motivation-8">Motivation</a></h2>
|
||
<p>Our goal is to translate simple mathematical expressions into postfix expressions
|
||
(or <a href="https://en.wikipedia.org/wiki/Reverse_Polish_notation">Reverse Polish notation</a>)
|
||
For simplicity, our expressions consist of ten digits <code>0</code>, ..., <code>9</code> and two
|
||
operations <code>+</code>, <code>-</code>. For example, the expression <code>2 + 4</code> is translated into
|
||
<code>2 4 +</code>.</p>
|
||
<h2 id="context-free-grammar-for-our-problem"><a class="header" href="#context-free-grammar-for-our-problem">Context Free Grammar for our problem</a></h2>
|
||
<p>Our task is translated infix expressions into postfix ones. Let's define a context
|
||
free grammar for a set of infix expressions over <code>0</code>, ..., <code>9</code>, <code>+</code>, and <code>-</code>,
|
||
where:</p>
|
||
<ul>
|
||
<li>terminal symbols: <code>0</code>, ..., <code>9</code>, <code>+</code>, <code>-</code></li>
|
||
<li>non-terminal symbols: <code>exp</code>, <code>term</code></li>
|
||
<li>start symbol is <code>exp</code></li>
|
||
<li>and the following are production rules</li>
|
||
</ul>
|
||
<pre><code class="language-ignore">exp -> exp + term
|
||
exp -> exp - term
|
||
exp -> term
|
||
term -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
||
</code></pre>
|
||
<p><strong>NOTE:</strong> This grammar should be further transformed depending on what we are going
|
||
to do with it. For example, we might need to remove left recursion. For more
|
||
details please see <a href="https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools">Compilers: Principles,Techniques, and Tools
|
||
</a>
|
||
(aka Dragon Book).</p>
|
||
<h2 id="solution"><a class="header" href="#solution">Solution</a></h2>
|
||
<p>We simply implement a recursive descent parser. For simplicity's sake, the code
|
||
panics when an expression is syntactically wrong (for example <code>2-34</code> or <code>2+5-</code>
|
||
are wrong according to the grammar definition).</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">pub struct Interpreter<'a> {
|
||
it: std::str::Chars<'a>,
|
||
}
|
||
|
||
impl<'a> Interpreter<'a> {
|
||
|
||
pub fn new(infix: &'a str) -> Self {
|
||
Self { it: infix.chars() }
|
||
}
|
||
|
||
fn next_char(&mut self) -> Option<char> {
|
||
self.it.next()
|
||
}
|
||
|
||
pub fn interpret(&mut self, out: &mut String) {
|
||
self.term(out);
|
||
|
||
while let Some(op) = self.next_char() {
|
||
if op == '+' || op == '-' {
|
||
self.term(out);
|
||
out.push(op);
|
||
} else {
|
||
panic!("Unexpected symbol '{}'", op);
|
||
}
|
||
}
|
||
}
|
||
|
||
fn term(&mut self, out: &mut String) {
|
||
match self.next_char() {
|
||
Some(ch) if ch.is_digit(10) => out.push(ch),
|
||
Some(ch) => panic!("Unexpected symbol '{}'", ch),
|
||
None => panic!("Unexpected end of string"),
|
||
}
|
||
}
|
||
}
|
||
|
||
pub fn main() {
|
||
let mut intr = Interpreter::new("2+3");
|
||
let mut postfix = String::new();
|
||
intr.interpret(&mut postfix);
|
||
assert_eq!(postfix, "23+");
|
||
|
||
intr = Interpreter::new("1-2+3-4");
|
||
postfix.clear();
|
||
intr.interpret(&mut postfix);
|
||
assert_eq!(postfix, "12-3+4-");
|
||
}
|
||
</code></pre></pre>
|
||
<h2 id="discussion-7"><a class="header" href="#discussion-7">Discussion</a></h2>
|
||
<p>There may be a wrong perception that the Interpreter design pattern is about design
|
||
grammars for formal languages and implementation of parsers for these grammars.
|
||
In fact, this pattern is about expressing problem instances in a more specific
|
||
way and implementing functions/classes/structs that solve these problem instances.
|
||
Rust language has <code>macro_rules!</code> that allow to define special syntax and rules
|
||
on how to expand this syntax into source code.</p>
|
||
<p>In the following example we create a simple <code>macro_rules!</code> that computes
|
||
<a href="https://en.wikipedia.org/wiki/Euclidean_distance">Euclidean length</a> of <code>n</code>
|
||
dimensional vectors. Writing <code>norm!(x,1,2)</code> might be easier to express and more
|
||
efficient than packing <code>x,1,2</code> into a <code>Vec</code> and calling a function computing
|
||
the length.</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">macro_rules! norm {
|
||
($($element:expr),*) => {
|
||
{
|
||
let mut n = 0.0;
|
||
$(
|
||
n += ($element as f64)*($element as f64);
|
||
)*
|
||
n.sqrt()
|
||
}
|
||
};
|
||
}
|
||
|
||
fn main() {
|
||
let x = -3f64;
|
||
let y = 4f64;
|
||
|
||
assert_eq!(3f64, norm!(x));
|
||
assert_eq!(5f64, norm!(x, y));
|
||
assert_eq!(0f64, norm!(0, 0, 0));
|
||
assert_eq!(1f64, norm!(0.5, -0.5, 0.5, -0.5));
|
||
}
|
||
</code></pre></pre>
|
||
<h2 id="see-also-10"><a class="header" href="#see-also-10">See also</a></h2>
|
||
<ul>
|
||
<li><a href="https://en.wikipedia.org/wiki/Interpreter_pattern">Interpreter pattern</a></li>
|
||
<li><a href="https://en.wikipedia.org/wiki/Context-free_grammar">Context free grammar</a></li>
|
||
<li><a href="https://doc.rust-lang.org/rust-by-example/macros.html">macro_rules!</a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="newtype"><a class="header" href="#newtype">Newtype</a></h1>
|
||
<p>What if in some cases we want a type to behave similar to another type or
|
||
enforce some behaviour at compile time when using only type aliases would
|
||
not be enough?</p>
|
||
<p>For example, if we want to create a custom <code>Display</code> implementation for <code>String</code>
|
||
due to security considerations (e.g. passwords).</p>
|
||
<p>For such cases we could use the <code>Newtype</code> pattern to provide <strong>type safety</strong>
|
||
and <strong>encapsulation</strong>.</p>
|
||
<h2 id="description-18"><a class="header" href="#description-18">Description</a></h2>
|
||
<p>Use a tuple struct with a single field to make an opaque wrapper for a type.
|
||
This creates a new type, rather than an alias to a type (<code>type</code> items).</p>
|
||
<h2 id="example-12"><a class="header" href="#example-12">Example</a></h2>
|
||
<pre><code class="language-rust ignore">// Some type, not necessarily in the same module or even crate.
|
||
struct Foo {
|
||
//..
|
||
}
|
||
|
||
impl Foo {
|
||
// These functions are not present on Bar.
|
||
//..
|
||
}
|
||
|
||
// The newtype.
|
||
pub struct Bar(Foo);
|
||
|
||
impl Bar {
|
||
// Constructor.
|
||
pub fn new(
|
||
//..
|
||
) -> Self {
|
||
|
||
//..
|
||
|
||
}
|
||
|
||
//..
|
||
}
|
||
|
||
fn main() {
|
||
let b = Bar::new(...);
|
||
|
||
// Foo and Bar are type incompatible, the following do not type check.
|
||
// let f: Foo = b;
|
||
// let b: Bar = Foo { ... };
|
||
}
|
||
</code></pre>
|
||
<h2 id="motivation-9"><a class="header" href="#motivation-9">Motivation</a></h2>
|
||
<p>The primary motivation for newtypes is abstraction. It allows you to share
|
||
implementation details between types while precisely controlling the interface.
|
||
By using a newtype rather than exposing the implementation type as part of an
|
||
API, it allows you to change implementation backwards compatibly.</p>
|
||
<p>Newtypes can be used for distinguishing units, e.g., wrapping <code>f64</code> to give
|
||
distinguishable <code>Miles</code> and <code>Kms</code>.</p>
|
||
<h2 id="advantages-11"><a class="header" href="#advantages-11">Advantages</a></h2>
|
||
<p>The wrapped and wrapper types are not type compatible (as opposed to using
|
||
<code>type</code>), so users of the newtype will never 'confuse' the wrapped and wrapper
|
||
types.</p>
|
||
<p>Newtypes are a zero-cost abstraction - there is no runtime overhead.</p>
|
||
<p>The privacy system ensures that users cannot access the wrapped type (if the
|
||
field is private, which it is by default).</p>
|
||
<h2 id="disadvantages-12"><a class="header" href="#disadvantages-12">Disadvantages</a></h2>
|
||
<p>The downside of newtypes (especially compared with type aliases), is that there
|
||
is no special language support. This means there can be <em>a lot</em> of boilerplate.
|
||
You need a 'pass through' method for every method you want to expose on the
|
||
wrapped type, and an impl for every trait you want to also be implemented for
|
||
the wrapper type.</p>
|
||
<h2 id="discussion-8"><a class="header" href="#discussion-8">Discussion</a></h2>
|
||
<p>Newtypes are very common in Rust code. Abstraction or representing units are the
|
||
most common uses, but they can be used for other reasons:</p>
|
||
<ul>
|
||
<li>restricting functionality (reduce the functions exposed or traits implemented),</li>
|
||
<li>making a type with copy semantics have move semantics,</li>
|
||
<li>abstraction by providing a more concrete type and thus hiding internal types,
|
||
e.g.,</li>
|
||
</ul>
|
||
<pre><code class="language-rust ignore">pub struct Foo(Bar<T1, T2>);
|
||
</code></pre>
|
||
<p>Here, <code>Bar</code> might be some public, generic type and <code>T1</code> and <code>T2</code> are some internal
|
||
types. Users of our module shouldn't know that we implement <code>Foo</code> by using a <code>Bar</code>,
|
||
but what we're really hiding here is the types <code>T1</code> and <code>T2</code>, and how they are used
|
||
with <code>Bar</code>.</p>
|
||
<h2 id="see-also-11"><a class="header" href="#see-also-11">See also</a></h2>
|
||
<ul>
|
||
<li><a href="https://doc.rust-lang.org/book/ch19-04-advanced-types.html?highlight=newtype#using-the-newtype-pattern-for-type-safety-and-abstraction">Advanced Types in the book</a></li>
|
||
<li><a href="https://wiki.haskell.org/Newtype">Newtypes in Haskell</a></li>
|
||
<li><a href="https://doc.rust-lang.org/stable/book/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases">Type aliases</a></li>
|
||
<li><a href="https://crates.io/crates/derive_more">derive_more</a>, a crate for deriving many
|
||
builtin traits on newtypes.</li>
|
||
<li><a href="https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html">The Newtype Pattern In Rust</a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="raii-with-guards"><a class="header" href="#raii-with-guards">RAII with guards</a></h1>
|
||
<h2 id="description-19"><a class="header" href="#description-19">Description</a></h2>
|
||
<p><a href="https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">RAII</a> stands for "Resource Acquisition is Initialisation" which is a
|
||
terrible name. The essence of the pattern is that resource initialisation is done
|
||
in the constructor of an object and finalisation in the destructor. This pattern
|
||
is extended in Rust by using an RAII object as a guard of some resource and relying
|
||
on the type system to ensure that access is always mediated by the guard object.</p>
|
||
<h2 id="example-13"><a class="header" href="#example-13">Example</a></h2>
|
||
<p>Mutex guards are the classic example of this pattern from the std library (this
|
||
is a simplified version of the real implementation):</p>
|
||
<pre><code class="language-rust ignore">use std::ops::Deref;
|
||
|
||
struct Foo {}
|
||
|
||
struct Mutex<T> {
|
||
// We keep a reference to our data: T here.
|
||
//..
|
||
}
|
||
|
||
struct MutexGuard<'a, T: 'a> {
|
||
data: &'a T,
|
||
//..
|
||
}
|
||
|
||
// Locking the mutex is explicit.
|
||
impl<T> Mutex<T> {
|
||
fn lock(&self) -> MutexGuard<T> {
|
||
// Lock the underlying OS mutex.
|
||
//..
|
||
|
||
// MutexGuard keeps a reference to self
|
||
MutexGuard {
|
||
data: self,
|
||
//..
|
||
}
|
||
}
|
||
}
|
||
|
||
// Destructor for unlocking the mutex.
|
||
impl<'a, T> Drop for MutexGuard<'a, T> {
|
||
fn drop(&mut self) {
|
||
// Unlock the underlying OS mutex.
|
||
//..
|
||
}
|
||
}
|
||
|
||
// Implementing Deref means we can treat MutexGuard like a pointer to T.
|
||
impl<'a, T> Deref for MutexGuard<'a, T> {
|
||
type Target = T;
|
||
|
||
fn deref(&self) -> &T {
|
||
self.data
|
||
}
|
||
}
|
||
|
||
fn baz(x: Mutex<Foo>) {
|
||
let xx = x.lock();
|
||
xx.foo(); // foo is a method on Foo.
|
||
// The borrow checker ensures we can't store a reference to the underlying
|
||
// Foo which will outlive the guard xx.
|
||
|
||
// x is unlocked when we exit this function and xx's destructor is executed.
|
||
}
|
||
</code></pre>
|
||
<h2 id="motivation-10"><a class="header" href="#motivation-10">Motivation</a></h2>
|
||
<p>Where a resource must be finalised after use, RAII can be used to do this
|
||
finalisation. If it is an error to access that resource after finalisation, then
|
||
this pattern can be used to prevent such errors.</p>
|
||
<h2 id="advantages-12"><a class="header" href="#advantages-12">Advantages</a></h2>
|
||
<p>Prevents errors where a resource is not finalised and where a resource is used
|
||
after finalisation.</p>
|
||
<h2 id="discussion-9"><a class="header" href="#discussion-9">Discussion</a></h2>
|
||
<p>RAII is a useful pattern for ensuring resources are properly deallocated or
|
||
finalised. We can make use of the borrow checker in Rust to statically prevent
|
||
errors stemming from using resources after finalisation takes place.</p>
|
||
<p>The core aim of the borrow checker is to ensure that references to data do not
|
||
outlive that data. The RAII guard pattern works because the guard object
|
||
contains a reference to the underlying resource and only exposes such
|
||
references. Rust ensures that the guard cannot outlive the underlying resource
|
||
and that references to the resource mediated by the guard cannot outlive the
|
||
guard. To see how this works it is helpful to examine the signature of <code>deref</code>
|
||
without lifetime elision:</p>
|
||
<pre><code class="language-rust ignore">fn deref<'a>(&'a self) -> &'a T {
|
||
//..
|
||
}
|
||
</code></pre>
|
||
<p>The returned reference to the resource has the same lifetime as <code>self</code> (<code>'a</code>).
|
||
The borrow checker therefore ensures that the lifetime of the reference to <code>T</code>
|
||
is shorter than the lifetime of <code>self</code>.</p>
|
||
<p>Note that implementing <code>Deref</code> is not a core part of this pattern, it only makes
|
||
using the guard object more ergonomic. Implementing a <code>get</code> method on the guard
|
||
works just as well.</p>
|
||
<h2 id="see-also-12"><a class="header" href="#see-also-12">See also</a></h2>
|
||
<p><a href="patterns/behavioural/../../idioms/dtor-finally.html">Finalisation in destructors idiom</a></p>
|
||
<p>RAII is a common pattern in C++: <a href="http://en.cppreference.com/w/cpp/language/raii">cppreference.com</a>,
|
||
<a href="https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">wikipedia</a>.</p>
|
||
<p><a href="https://doc.rust-lang.org/1.0.0/style/ownership/raii.html">Style guide entry</a>
|
||
(currently just a placeholder).</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="strategy-aka-policy"><a class="header" href="#strategy-aka-policy">Strategy (aka Policy)</a></h1>
|
||
<h2 id="description-20"><a class="header" href="#description-20">Description</a></h2>
|
||
<p>The <a href="https://en.wikipedia.org/wiki/Strategy_pattern">Strategy design pattern</a>
|
||
is a technique that enables separation of concerns.
|
||
It also allows to decouple software modules through <a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion</a>.</p>
|
||
<p>The basic idea behind the Strategy pattern is that, given an algorithm solving
|
||
a particular problem, we define only the skeleton of the algorithm at an abstract
|
||
level, and we separate the specific algorithm’s implementation into different parts.</p>
|
||
<p>In this way, a client using the algorithm may choose a specific implementation,
|
||
while the general algorithm workflow remains the same. In other words, the abstract
|
||
specification of the class does not depend on the specific implementation of the
|
||
derived class, but specific implementation must adhere to the abstract specification.
|
||
This is why we call it "Dependency Inversion".</p>
|
||
<h2 id="motivation-11"><a class="header" href="#motivation-11">Motivation</a></h2>
|
||
<p>Imagine we are working on a project that generates reports every month.
|
||
We need the reports to be generated in different formats (strategies), e.g.,
|
||
in <code>JSON</code> or <code>Plain Text</code> formats.
|
||
But things vary over time, and we don't know what kind of requirement we may get
|
||
in the future. For example, we may need to generate our report in a completely new
|
||
format, or just modify one of the existing formats.</p>
|
||
<h2 id="example-14"><a class="header" href="#example-14">Example</a></h2>
|
||
<p>In this example our invariants (or abstractions) are <code>Context</code>, <code>Formatter</code>,
|
||
and <code>Report</code>, while <code>Text</code> and <code>Json</code> are our strategy structs. These strategies
|
||
have to implement the <code>Formatter</code> trait.</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">use std::collections::HashMap;
|
||
|
||
type Data = HashMap<String, u32>;
|
||
|
||
trait Formatter {
|
||
fn format(&self, data: &Data, buf: &mut String);
|
||
}
|
||
|
||
struct Report;
|
||
|
||
impl Report {
|
||
// Write should be used but we kept it as String to ignore error handling
|
||
fn generate<T: Formatter>(g: T, s: &mut String) {
|
||
// backend operations...
|
||
let mut data = HashMap::new();
|
||
data.insert("one".to_string(), 1);
|
||
data.insert("two".to_string(), 2);
|
||
// generate report
|
||
g.format(&data, s);
|
||
}
|
||
}
|
||
|
||
struct Text;
|
||
impl Formatter for Text {
|
||
fn format(&self, data: &Data, buf: &mut String) {
|
||
for (k, v) in data {
|
||
let entry = format!("{} {}\n", k, v);
|
||
buf.push_str(&entry);
|
||
}
|
||
}
|
||
}
|
||
|
||
struct Json;
|
||
impl Formatter for Json {
|
||
fn format(&self, data: &Data, buf: &mut String) {
|
||
buf.push('[');
|
||
for (k, v) in data.into_iter() {
|
||
let entry = format!(r#"{{"{}":"{}"}}"#, k, v);
|
||
buf.push_str(&entry);
|
||
buf.push(',');
|
||
}
|
||
buf.pop(); // remove extra , at the end
|
||
buf.push(']');
|
||
}
|
||
}
|
||
|
||
fn main() {
|
||
let mut s = String::from("");
|
||
Report::generate(Text, &mut s);
|
||
assert!(s.contains("one 1"));
|
||
assert!(s.contains("two 2"));
|
||
|
||
s.clear(); // reuse the same buffer
|
||
Report::generate(Json, &mut s);
|
||
assert!(s.contains(r#"{"one":"1"}"#));
|
||
assert!(s.contains(r#"{"two":"2"}"#));
|
||
}
|
||
</code></pre></pre>
|
||
<h2 id="advantages-13"><a class="header" href="#advantages-13">Advantages</a></h2>
|
||
<p>The main advantage is separation of concerns. For example, in this case <code>Report</code>
|
||
does not know anything about specific implementations of <code>Json</code> and <code>Text</code>,
|
||
whereas the output implementations does not care about how data is preprocessed,
|
||
stored, and fetched. The only thing they have to know is context and a specific
|
||
trait and method to implement, i.e,<code>Formatter</code> and <code>run</code>.</p>
|
||
<h2 id="disadvantages-13"><a class="header" href="#disadvantages-13">Disadvantages</a></h2>
|
||
<p>For each strategy there must be implemented at least one module, so number of modules
|
||
increases with number of strategies. If there are many strategies to choose from
|
||
then users have to know how strategies differ from one another.</p>
|
||
<h2 id="discussion-10"><a class="header" href="#discussion-10">Discussion</a></h2>
|
||
<p>In the previous example all strategies are implemented in a single file.
|
||
Ways of providing different strategies includes:</p>
|
||
<ul>
|
||
<li>All in one file (as shown in this example, similar to being separated as modules)</li>
|
||
<li>Separated as modules, E.g. <code>formatter::json</code> module, <code>formatter::text</code> module</li>
|
||
<li>Use compiler feature flags, E.g. <code>json</code> feature, <code>text</code> feature</li>
|
||
<li>Separated as crates, E.g. <code>json</code> crate, <code>text</code> crate</li>
|
||
</ul>
|
||
<p>Serde crate is a good example of the <code>Strategy</code> pattern in action. Serde allows
|
||
<a href="https://serde.rs/custom-serialization.html">full customization</a> of the serialization
|
||
behavior by manually implementing <code>Serialize</code> and <code>Deserialize</code> traits for our
|
||
type. For example, we could easily swap <code>serde_json</code> with <code>serde_cbor</code> since they
|
||
expose similar methods. Having this makes the helper crate <code>serde_transcode</code> much
|
||
more useful and ergonomic.</p>
|
||
<p>However, we don't need to use traits in order to design this pattern in Rust.</p>
|
||
<p>The following toy example demonstrates the idea of the Strategy pattern using Rust
|
||
<code>closures</code>:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">struct Adder;
|
||
impl Adder {
|
||
pub fn add<F>(x: u8, y: u8, f: F) -> u8
|
||
where
|
||
F: Fn(u8, u8) -> u8,
|
||
{
|
||
f(x, y)
|
||
}
|
||
}
|
||
|
||
fn main() {
|
||
let arith_adder = |x, y| x + y;
|
||
let bool_adder = |x, y| {
|
||
if x == 1 || y == 1 {
|
||
1
|
||
} else {
|
||
0
|
||
}
|
||
};
|
||
let custom_adder = |x, y| 2 * x + y;
|
||
|
||
assert_eq!(9, Adder::add(4, 5, arith_adder));
|
||
assert_eq!(0, Adder::add(0, 0, bool_adder));
|
||
assert_eq!(5, Adder::add(1, 3, custom_adder));
|
||
}
|
||
|
||
</code></pre></pre>
|
||
<p>In fact, Rust already uses this idea for <code>Options</code>'s <code>map</code> method:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">fn main() {
|
||
let val = Some("Rust");
|
||
|
||
let len_strategy = |s: &str| s.len();
|
||
assert_eq!(4, val.map(len_strategy).unwrap());
|
||
|
||
let first_byte_strategy = |s: &str| s.bytes().next().unwrap();
|
||
assert_eq!(82, val.map(first_byte_strategy).unwrap());
|
||
}
|
||
</code></pre></pre>
|
||
<h2 id="see-also-13"><a class="header" href="#see-also-13">See also</a></h2>
|
||
<ul>
|
||
<li><a href="https://en.wikipedia.org/wiki/Strategy_pattern">Strategy Pattern</a></li>
|
||
<li><a href="https://en.wikipedia.org/wiki/Dependency_injection">Dependency Injection</a></li>
|
||
<li><a href="https://en.wikipedia.org/wiki/Modern_C++_Design#Policy-based_design">Policy Based Design</a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="visitor"><a class="header" href="#visitor">Visitor</a></h1>
|
||
<h2 id="description-21"><a class="header" href="#description-21">Description</a></h2>
|
||
<p>A visitor encapsulates an algorithm that operates over a heterogeneous
|
||
collection of objects. It allows multiple different algorithms to be written
|
||
over the same data without having to modify the data (or their primary
|
||
behaviour).</p>
|
||
<p>Furthermore, the visitor pattern allows separating the traversal of
|
||
a collection of objects from the operations performed on each object.</p>
|
||
<h2 id="example-15"><a class="header" href="#example-15">Example</a></h2>
|
||
<pre><code class="language-rust ignore">// The data we will visit
|
||
mod ast {
|
||
pub enum Stmt {
|
||
Expr(Expr),
|
||
Let(Name, Expr),
|
||
}
|
||
|
||
pub struct Name {
|
||
value: String,
|
||
}
|
||
|
||
pub enum Expr {
|
||
IntLit(i64),
|
||
Add(Box<Expr>, Box<Expr>),
|
||
Sub(Box<Expr>, Box<Expr>),
|
||
}
|
||
}
|
||
|
||
// The abstract visitor
|
||
mod visit {
|
||
use ast::*;
|
||
|
||
pub trait Visitor<T> {
|
||
fn visit_name(&mut self, n: &Name) -> T;
|
||
fn visit_stmt(&mut self, s: &Stmt) -> T;
|
||
fn visit_expr(&mut self, e: &Expr) -> T;
|
||
}
|
||
}
|
||
|
||
use visit::*;
|
||
use ast::*;
|
||
|
||
// An example concrete implementation - walks the AST interpreting it as code.
|
||
struct Interpreter;
|
||
impl Visitor<i64> for Interpreter {
|
||
fn visit_name(&mut self, n: &Name) -> i64 { panic!() }
|
||
fn visit_stmt(&mut self, s: &Stmt) -> i64 {
|
||
match *s {
|
||
Stmt::Expr(ref e) => self.visit_expr(e),
|
||
Stmt::Let(..) => unimplemented!(),
|
||
}
|
||
}
|
||
|
||
fn visit_expr(&mut self, e: &Expr) -> i64 {
|
||
match *e {
|
||
Expr::IntLit(n) => n,
|
||
Expr::Add(ref lhs, ref rhs) => self.visit_expr(lhs) + self.visit_expr(rhs),
|
||
Expr::Sub(ref lhs, ref rhs) => self.visit_expr(lhs) - self.visit_expr(rhs),
|
||
}
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>One could implement further visitors, for example a type checker, without having
|
||
to modify the AST data.</p>
|
||
<h2 id="motivation-12"><a class="header" href="#motivation-12">Motivation</a></h2>
|
||
<p>The visitor pattern is useful anywhere that you want to apply an algorithm to
|
||
heterogeneous data. If data is homogeneous, you can use an iterator-like pattern.
|
||
Using a visitor object (rather than a functional approach) allows the visitor to
|
||
be stateful and thus communicate information between nodes.</p>
|
||
<h2 id="discussion-11"><a class="header" href="#discussion-11">Discussion</a></h2>
|
||
<p>It is common for the <code>visit_*</code> methods to return void (as opposed to in the
|
||
example). In that case it is possible to factor out the traversal code and share
|
||
it between algorithms (and also to provide noop default methods). In Rust, the
|
||
common way to do this is to provide <code>walk_*</code> functions for each datum. For
|
||
example,</p>
|
||
<pre><code class="language-rust ignore">pub fn walk_expr(visitor: &mut Visitor, e: &Expr) {
|
||
match *e {
|
||
Expr::IntLit(_) => {},
|
||
Expr::Add(ref lhs, ref rhs) => {
|
||
visitor.visit_expr(lhs);
|
||
visitor.visit_expr(rhs);
|
||
}
|
||
Expr::Sub(ref lhs, ref rhs) => {
|
||
visitor.visit_expr(lhs);
|
||
visitor.visit_expr(rhs);
|
||
}
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>In other languages (e.g., Java) it is common for data to have an <code>accept</code> method
|
||
which performs the same duty.</p>
|
||
<h2 id="see-also-14"><a class="header" href="#see-also-14">See also</a></h2>
|
||
<p>The visitor pattern is a common pattern in most OO languages.</p>
|
||
<p><a href="https://en.wikipedia.org/wiki/Visitor_pattern">Wikipedia article</a></p>
|
||
<p>The <a href="patterns/behavioural/../creational/fold.html">fold</a> pattern is similar to visitor but produces
|
||
a new version of the visited data structure.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="creational-patterns"><a class="header" href="#creational-patterns">Creational Patterns</a></h1>
|
||
<p>From <a href="https://en.wikipedia.org/wiki/Creational_pattern">Wikipedia</a>:</p>
|
||
<blockquote>
|
||
<p>Design patterns that deal with object creation mechanisms, trying to create objects
|
||
in a manner suitable to the situation. The basic form of object creation could
|
||
result in design problems or in added complexity to the design. Creational design
|
||
patterns solve this problem by somehow controlling this object creation.</p>
|
||
</blockquote>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="builder"><a class="header" href="#builder">Builder</a></h1>
|
||
<h2 id="description-22"><a class="header" href="#description-22">Description</a></h2>
|
||
<p>Construct an object with calls to a builder helper.</p>
|
||
<h2 id="example-16"><a class="header" href="#example-16">Example</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>#[derive(Debug, PartialEq)]
|
||
pub struct Foo {
|
||
// Lots of complicated fields.
|
||
bar: String,
|
||
}
|
||
|
||
impl Foo {
|
||
// This method will help users to discover the builder
|
||
pub fn builder() -> FooBuilder {
|
||
FooBuilder::default()
|
||
}
|
||
}
|
||
|
||
#[derive(Default)]
|
||
pub struct FooBuilder {
|
||
// Probably lots of optional fields.
|
||
bar: String,
|
||
}
|
||
|
||
impl FooBuilder {
|
||
pub fn new(/* ... */) -> FooBuilder {
|
||
// Set the minimally required fields of Foo.
|
||
FooBuilder {
|
||
bar: String::from("X"),
|
||
}
|
||
}
|
||
|
||
pub fn name(mut self, bar: String) -> FooBuilder {
|
||
// Set the name on the builder itself, and return the builder by value.
|
||
self.bar = bar;
|
||
self
|
||
}
|
||
|
||
// If we can get away with not consuming the Builder here, that is an
|
||
// advantage. It means we can use the FooBuilder as a template for constructing
|
||
// many Foos.
|
||
pub fn build(self) -> Foo {
|
||
// Create a Foo from the FooBuilder, applying all settings in FooBuilder
|
||
// to Foo.
|
||
Foo { bar: self.bar }
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn builder_test() {
|
||
let foo = Foo {
|
||
bar: String::from("Y"),
|
||
};
|
||
let foo_from_builder: Foo = FooBuilder::new().name(String::from("Y")).build();
|
||
assert_eq!(foo, foo_from_builder);
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="motivation-13"><a class="header" href="#motivation-13">Motivation</a></h2>
|
||
<p>Useful when you would otherwise require many constructors or where
|
||
construction has side effects.</p>
|
||
<h2 id="advantages-14"><a class="header" href="#advantages-14">Advantages</a></h2>
|
||
<p>Separates methods for building from other methods.</p>
|
||
<p>Prevents proliferation of constructors</p>
|
||
<p>Can be used for one-liner initialisation as well as more complex construction.</p>
|
||
<h2 id="disadvantages-14"><a class="header" href="#disadvantages-14">Disadvantages</a></h2>
|
||
<p>More complex than creating a struct object directly, or a simple constructor
|
||
function.</p>
|
||
<h2 id="discussion-12"><a class="header" href="#discussion-12">Discussion</a></h2>
|
||
<p>This pattern is seen more frequently in Rust (and for simpler objects) than in
|
||
many other languages because Rust lacks overloading. Since you can only have a
|
||
single method with a given name, having multiple constructors is less nice in
|
||
Rust than in C++, Java, or others.</p>
|
||
<p>This pattern is often used where the builder object is useful in its own right,
|
||
rather than being just a builder. For example, see
|
||
<a href="https://doc.rust-lang.org/std/process/struct.Command.html"><code>std::process::Command</code></a>
|
||
is a builder for <a href="https://doc.rust-lang.org/std/process/struct.Child.html"><code>Child</code></a>
|
||
(a process). In these cases, the <code>T</code> and <code>TBuilder</code> pattern
|
||
of naming is not used.</p>
|
||
<p>The example takes and returns the builder by value. It is often more ergonomic
|
||
(and more efficient) to take and return the builder as a mutable reference. The
|
||
borrow checker makes this work naturally. This approach has the advantage that
|
||
one can write code like</p>
|
||
<pre><code class="language-rust ignore">let mut fb = FooBuilder::new();
|
||
fb.a();
|
||
fb.b();
|
||
let f = fb.build();
|
||
</code></pre>
|
||
<p>as well as the <code>FooBuilder::new().a().b().build()</code> style.</p>
|
||
<h2 id="see-also-15"><a class="header" href="#see-also-15">See also</a></h2>
|
||
<ul>
|
||
<li><a href="https://web.archive.org/web/20210104103100/https://doc.rust-lang.org/1.12.0/style/ownership/builders.html">Description in the style guide</a></li>
|
||
<li><a href="https://crates.io/crates/derive_builder">derive_builder</a>, a crate for automatically
|
||
implementing this pattern while avoiding the boilerplate.</li>
|
||
<li><a href="patterns/creational/../../idioms/ctor.html">Constructor pattern</a> for when construction is simpler.</li>
|
||
<li><a href="https://en.wikipedia.org/wiki/Builder_pattern">Builder pattern (wikipedia)</a></li>
|
||
<li><a href="https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder">Construction of complex values</a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="fold"><a class="header" href="#fold">Fold</a></h1>
|
||
<h2 id="description-23"><a class="header" href="#description-23">Description</a></h2>
|
||
<p>Run an algorithm over each item in a collection of data to create a new item,
|
||
thus creating a whole new collection.</p>
|
||
<p>The etymology here is unclear to me. The terms 'fold' and 'folder' are used
|
||
in the Rust compiler, although it appears to me to be more like a map than a
|
||
fold in the usual sense. See the discussion below for more details.</p>
|
||
<h2 id="example-17"><a class="header" href="#example-17">Example</a></h2>
|
||
<pre><code class="language-rust ignore">// The data we will fold, a simple AST.
|
||
mod ast {
|
||
pub enum Stmt {
|
||
Expr(Box<Expr>),
|
||
Let(Box<Name>, Box<Expr>),
|
||
}
|
||
|
||
pub struct Name {
|
||
value: String,
|
||
}
|
||
|
||
pub enum Expr {
|
||
IntLit(i64),
|
||
Add(Box<Expr>, Box<Expr>),
|
||
Sub(Box<Expr>, Box<Expr>),
|
||
}
|
||
}
|
||
|
||
// The abstract folder
|
||
mod fold {
|
||
use ast::*;
|
||
|
||
pub trait Folder {
|
||
// A leaf node just returns the node itself. In some cases, we can do this
|
||
// to inner nodes too.
|
||
fn fold_name(&mut self, n: Box<Name>) -> Box<Name> { n }
|
||
// Create a new inner node by folding its children.
|
||
fn fold_stmt(&mut self, s: Box<Stmt>) -> Box<Stmt> {
|
||
match *s {
|
||
Stmt::Expr(e) => Box::new(Stmt::Expr(self.fold_expr(e))),
|
||
Stmt::Let(n, e) => Box::new(Stmt::Let(self.fold_name(n), self.fold_expr(e))),
|
||
}
|
||
}
|
||
fn fold_expr(&mut self, e: Box<Expr>) -> Box<Expr> { ... }
|
||
}
|
||
}
|
||
|
||
use fold::*;
|
||
use ast::*;
|
||
|
||
// An example concrete implementation - renames every name to 'foo'.
|
||
struct Renamer;
|
||
impl Folder for Renamer {
|
||
fn fold_name(&mut self, n: Box<Name>) -> Box<Name> {
|
||
Box::new(Name { value: "foo".to_owned() })
|
||
}
|
||
// Use the default methods for the other nodes.
|
||
}
|
||
</code></pre>
|
||
<p>The result of running the <code>Renamer</code> on an AST is a new AST identical to the old
|
||
one, but with every name changed to <code>foo</code>. A real life folder might have some
|
||
state preserved between nodes in the struct itself.</p>
|
||
<p>A folder can also be defined to map one data structure to a different (but
|
||
usually similar) data structure. For example, we could fold an AST into a HIR
|
||
tree (HIR stands for high-level intermediate representation).</p>
|
||
<h2 id="motivation-14"><a class="header" href="#motivation-14">Motivation</a></h2>
|
||
<p>It is common to want to map a data structure by performing some operation on
|
||
each node in the structure. For simple operations on simple data structures,
|
||
this can be done using <code>Iterator::map</code>. For more complex operations, perhaps
|
||
where earlier nodes can affect the operation on later nodes, or where iteration
|
||
over the data structure is non-trivial, using the fold pattern is more
|
||
appropriate.</p>
|
||
<p>Like the visitor pattern, the fold pattern allows us to separate traversal of a
|
||
data structure from the operations performed to each node.</p>
|
||
<h2 id="discussion-13"><a class="header" href="#discussion-13">Discussion</a></h2>
|
||
<p>Mapping data structures in this fashion is common in functional languages. In OO
|
||
languages, it would be more common to mutate the data structure in place. The
|
||
'functional' approach is common in Rust, mostly due to the preference for
|
||
immutability. Using fresh data structures, rather than mutating old ones, makes
|
||
reasoning about the code easier in most circumstances.</p>
|
||
<p>The trade-off between efficiency and reusability can be tweaked by changing how
|
||
nodes are accepted by the <code>fold_*</code> methods.</p>
|
||
<p>In the above example we operate on <code>Box</code> pointers. Since these own their data
|
||
exclusively, the original copy of the data structure cannot be re-used. On the
|
||
other hand if a node is not changed, reusing it is very efficient.</p>
|
||
<p>If we were to operate on borrowed references, the original data structure can be
|
||
reused; however, a node must be cloned even if unchanged, which can be
|
||
expensive.</p>
|
||
<p>Using a reference counted pointer gives the best of both worlds - we can reuse
|
||
the original data structure, and we don't need to clone unchanged nodes. However,
|
||
they are less ergonomic to use and mean that the data structures cannot be
|
||
mutable.</p>
|
||
<h2 id="see-also-16"><a class="header" href="#see-also-16">See also</a></h2>
|
||
<p>Iterators have a <code>fold</code> method, however this folds a data structure into a
|
||
value, rather than into a new data structure. An iterator's <code>map</code> is more like
|
||
this fold pattern.</p>
|
||
<p>In other languages, fold is usually used in the sense of Rust's iterators,
|
||
rather than this pattern. Some functional languages have powerful constructs for
|
||
performing flexible maps over data structures.</p>
|
||
<p>The <a href="patterns/creational/../behavioural/visitor.html">visitor</a> pattern is closely related to fold.
|
||
They share the concept of walking a data structure performing an operation on
|
||
each node. However, the visitor does not create a new data structure nor consume
|
||
the old one.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="structural-patterns"><a class="header" href="#structural-patterns">Structural Patterns</a></h1>
|
||
<p>From <a href="https://en.wikipedia.org/wiki/Structural_pattern">Wikipedia</a>:</p>
|
||
<blockquote>
|
||
<p>Design patterns that ease the design by identifying a simple way to realize relationships
|
||
among entities.</p>
|
||
</blockquote>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="compose-structs-together-for-better-borrowing"><a class="header" href="#compose-structs-together-for-better-borrowing">Compose structs together for better borrowing</a></h1>
|
||
<p>TODO - this is not a very snappy name</p>
|
||
<h2 id="description-24"><a class="header" href="#description-24">Description</a></h2>
|
||
<p>Sometimes a large struct will cause issues with the borrow checker - although
|
||
fields can be borrowed independently, sometimes the whole struct ends up being
|
||
used at once, preventing other uses. A solution might be to decompose the struct
|
||
into several smaller structs. Then compose these together into the original
|
||
struct. Then each struct can be borrowed separately and have more flexible
|
||
behaviour.</p>
|
||
<p>This will often lead to a better design in other ways: applying this design
|
||
pattern often reveals smaller units of functionality.</p>
|
||
<h2 id="example-18"><a class="header" href="#example-18">Example</a></h2>
|
||
<p>Here is a contrived example of where the borrow checker foils us in our plan to
|
||
use a struct:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>struct A {
|
||
f1: u32,
|
||
f2: u32,
|
||
f3: u32,
|
||
}
|
||
|
||
fn foo(a: &mut A) -> &u32 { &a.f2 }
|
||
fn bar(a: &mut A) -> u32 { a.f1 + a.f3 }
|
||
|
||
fn baz(a: &mut A) {
|
||
// The later usage of x causes a to be borrowed for the rest of the function.
|
||
let x = foo(a);
|
||
// Borrow checker error:
|
||
// let y = bar(a); // ~ ERROR: cannot borrow `*a` as mutable more than once
|
||
// at a time
|
||
println!("{}", x);
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<p>We can apply this design pattern and refactor <code>A</code> into two smaller structs, thus
|
||
solving the borrow checking issue:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>// A is now composed of two structs - B and C.
|
||
struct A {
|
||
b: B,
|
||
c: C,
|
||
}
|
||
struct B {
|
||
f2: u32,
|
||
}
|
||
struct C {
|
||
f1: u32,
|
||
f3: u32,
|
||
}
|
||
|
||
// These functions take a B or C, rather than A.
|
||
fn foo(b: &mut B) -> &u32 { &b.f2 }
|
||
fn bar(c: &mut C) -> u32 { c.f1 + c.f3 }
|
||
|
||
fn baz(a: &mut A) {
|
||
let x = foo(&mut a.b);
|
||
// Now it's OK!
|
||
let y = bar(&mut a.c);
|
||
println!("{}", x);
|
||
}
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="motivation-15"><a class="header" href="#motivation-15">Motivation</a></h2>
|
||
<p>TODO Why and where you should use the pattern</p>
|
||
<h2 id="advantages-15"><a class="header" href="#advantages-15">Advantages</a></h2>
|
||
<p>Lets you work around limitations in the borrow checker.</p>
|
||
<p>Often produces a better design.</p>
|
||
<h2 id="disadvantages-15"><a class="header" href="#disadvantages-15">Disadvantages</a></h2>
|
||
<p>Leads to more verbose code.</p>
|
||
<p>Sometimes, the smaller structs are not good abstractions, and so we end up with
|
||
a worse design. That is probably a 'code smell', indicating that the program
|
||
should be refactored in some way.</p>
|
||
<h2 id="discussion-14"><a class="header" href="#discussion-14">Discussion</a></h2>
|
||
<p>This pattern is not required in languages that don't have a borrow checker, so
|
||
in that sense is unique to Rust. However, making smaller units of functionality
|
||
often leads to cleaner code: a widely acknowledged principle of software
|
||
engineering, independent of the language.</p>
|
||
<p>This pattern relies on Rust's borrow checker to be able to borrow fields
|
||
independently of each other. In the example, the borrow checker knows that <code>a.b</code>
|
||
and <code>a.c</code> are distinct and can be borrowed independently, it does not try to
|
||
borrow all of <code>a</code>, which would make this pattern useless.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="prefer-small-crates"><a class="header" href="#prefer-small-crates">Prefer small crates</a></h1>
|
||
<h2 id="description-25"><a class="header" href="#description-25">Description</a></h2>
|
||
<p>Prefer small crates that do one thing well.</p>
|
||
<p>Cargo and crates.io make it easy to add third-party libraries, much more so than
|
||
in say C or C++. Moreover, since packages on crates.io cannot be edited or removed
|
||
after publication, any build that works now should continue to work in the future.
|
||
We should take advantage of this tooling, and use smaller, more fine-grained dependencies.</p>
|
||
<h2 id="advantages-16"><a class="header" href="#advantages-16">Advantages</a></h2>
|
||
<ul>
|
||
<li>Small crates are easier to understand, and encourage more modular code.</li>
|
||
<li>Crates allow for re-using code between projects.
|
||
For example, the <code>url</code> crate was developed as part of the Servo browser engine,
|
||
but has since found wide use outside the project.</li>
|
||
<li>Since the compilation unit
|
||
of Rust is the crate, splitting a project into multiple crates can allow more of
|
||
the code to be built in parallel.</li>
|
||
</ul>
|
||
<h2 id="disadvantages-16"><a class="header" href="#disadvantages-16">Disadvantages</a></h2>
|
||
<ul>
|
||
<li>This can lead to "dependency hell", when a project depends on multiple conflicting
|
||
versions of a crate at the same time. For example, the <code>url</code> crate has both versions
|
||
1.0 and 0.5. Since the <code>Url</code> from <code>url:1.0</code> and the <code>Url</code> from <code>url:0.5</code> are
|
||
different types, an HTTP client that uses <code>url:0.5</code> would not accept <code>Url</code> values
|
||
from a web scraper that uses <code>url:1.0</code>.</li>
|
||
<li>Packages on crates.io are not curated. A crate may be poorly written, have
|
||
unhelpful documentation, or be outright malicious.</li>
|
||
<li>Two small crates may be less optimized than one large one, since the compiler
|
||
does not perform link-time optimization (LTO) by default.</li>
|
||
</ul>
|
||
<h2 id="examples-1"><a class="header" href="#examples-1">Examples</a></h2>
|
||
<p>The <a href="https://crates.io/crates/ref_slice"><code>ref_slice</code></a> crate provides functions
|
||
for converting <code>&T</code> to <code>&[T]</code>.</p>
|
||
<p>The <a href="https://crates.io/crates/url"><code>url</code></a> crate provides tools for working with
|
||
URLs.</p>
|
||
<p>The <a href="https://crates.io/crates/num_cpus"><code>num_cpus</code></a> crate provides a function to
|
||
query the number of CPUs on a machine.</p>
|
||
<h2 id="see-also-17"><a class="header" href="#see-also-17">See also</a></h2>
|
||
<ul>
|
||
<li><a href="https://crates.io/">crates.io: The Rust community crate host</a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="contain-unsafety-in-small-modules"><a class="header" href="#contain-unsafety-in-small-modules">Contain unsafety in small modules</a></h1>
|
||
<h2 id="description-26"><a class="header" href="#description-26">Description</a></h2>
|
||
<p>If you have <code>unsafe</code> code, create the smallest possible module that can uphold
|
||
the needed invariants to build a minimal safe interface upon the unsafety. Embed
|
||
this into a larger module that contains only safe code and presents an ergonomic
|
||
interface. Note that the outer module can contain unsafe functions and methods
|
||
that call directly into the unsafe code. Users may use this to gain speed benefits.</p>
|
||
<h2 id="advantages-17"><a class="header" href="#advantages-17">Advantages</a></h2>
|
||
<ul>
|
||
<li>This restricts the unsafe code that must be audited</li>
|
||
<li>Writing the outer module is much easier, since you can count on the guarantees
|
||
of the inner module</li>
|
||
</ul>
|
||
<h2 id="disadvantages-17"><a class="header" href="#disadvantages-17">Disadvantages</a></h2>
|
||
<ul>
|
||
<li>Sometimes, it may be hard to find a suitable interface.</li>
|
||
<li>The abstraction may introduce inefficiencies.</li>
|
||
</ul>
|
||
<h2 id="examples-2"><a class="header" href="#examples-2">Examples</a></h2>
|
||
<ul>
|
||
<li>The <a href="https://docs.rs/toolshed"><code>toolshed</code></a> crate contains its unsafe operations
|
||
in submodules, presenting a safe interface to users.</li>
|
||
<li><code>std</code>'s <code>String</code> class is a wrapper over <code>Vec<u8></code> with the added invariant
|
||
that the contents must be valid UTF-8. The operations on <code>String</code> ensure this
|
||
behavior.
|
||
However, users have the option of using an <code>unsafe</code> method to create a <code>String</code>,
|
||
in which case the onus is on them to guarantee the validity of the contents.</li>
|
||
</ul>
|
||
<h2 id="see-also-18"><a class="header" href="#see-also-18">See also</a></h2>
|
||
<ul>
|
||
<li><a href="https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html">Ralf Jung's Blog about invariants in unsafe code</a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="ffi-patterns"><a class="header" href="#ffi-patterns">FFI Patterns</a></h1>
|
||
<p>Writing FFI code is an entire course in itself.
|
||
However, there are several idioms here that can act as pointers, and avoid traps
|
||
for inexperienced users of unsafe Rust.</p>
|
||
<p>This section contains design patterns that may be useful when doing FFI.</p>
|
||
<ol>
|
||
<li>
|
||
<p><a href="patterns/ffi/./export.html">Object-Based API</a> design that has good memory safety characteristics,
|
||
and a clean boundary of what is safe and what is unsafe</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="patterns/ffi/./wrappers.html">Type Consolidation into Wrappers</a> - group multiple Rust types
|
||
together into an opaque "object"</p>
|
||
</li>
|
||
</ol>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="object-based-apis"><a class="header" href="#object-based-apis">Object-Based APIs</a></h1>
|
||
<h2 id="description-27"><a class="header" href="#description-27">Description</a></h2>
|
||
<p>When designing APIs in Rust which are exposed to other languages, there are some
|
||
important design principles which are contrary to normal Rust API design:</p>
|
||
<ol>
|
||
<li>All Encapsulated types should be <em>owned</em> by Rust, <em>managed</em> by the user,
|
||
and <em>opaque</em>.</li>
|
||
<li>All Transactional data types should be <em>owned</em> by the user, and <em>transparent</em>.</li>
|
||
<li>All library behavior should be functions acting upon Encapsulated types.</li>
|
||
<li>All library behavior should be encapsulated into types not based on structure,
|
||
but <em>provenance/lifetime</em>.</li>
|
||
</ol>
|
||
<h2 id="motivation-16"><a class="header" href="#motivation-16">Motivation</a></h2>
|
||
<p>Rust has built-in FFI support to other languages.
|
||
It does this by providing a way for crate authors to provide C-compatible APIs
|
||
through different ABIs (though that is unimportant to this practice).</p>
|
||
<p>Well-designed Rust FFI follows C API design principles, while compromising the
|
||
design in Rust as little as possible. There are three goals with any foreign API:</p>
|
||
<ol>
|
||
<li>Make it easy to use in the target language.</li>
|
||
<li>Avoid the API dictating internal unsafety on the Rust side as much as possible.</li>
|
||
<li>Keep the potential for memory unsafety and Rust <code>undefined behaviour</code> as small
|
||
as possible.</li>
|
||
</ol>
|
||
<p>Rust code must trust the memory safety of the foreign language beyond a certain
|
||
point. However, every bit of <code>unsafe</code> code on the Rust side is an opportunity for
|
||
bugs, or to exacerbate <code>undefined behaviour</code>.</p>
|
||
<p>For example, if a pointer provenance is wrong, that may be a segfault due to
|
||
invalid memory access. But if it is manipulated by unsafe code, it could become
|
||
full-blown heap corruption.</p>
|
||
<p>The Object-Based API design allows for writing shims that have good memory safety
|
||
characteristics, and a clean boundary of what is safe and what is <code>unsafe</code>.</p>
|
||
<h2 id="code-example-3"><a class="header" href="#code-example-3">Code Example</a></h2>
|
||
<p>The POSIX standard defines the API to access an on-file database, known as <a href="https://web.archive.org/web/20210105035602/https://www.mankier.com/0p/ndbm.h">DBM</a>.
|
||
It is an excellent example of an "object-based" API.</p>
|
||
<p>Here is the definition in C, which hopefully should be easy to read for those
|
||
involved in FFI. The commentary below should help explain it for those who
|
||
miss the subtleties.</p>
|
||
<pre><code class="language-C">struct DBM;
|
||
typedef struct { void *dptr, size_t dsize } datum;
|
||
|
||
int dbm_clearerr(DBM *);
|
||
void dbm_close(DBM *);
|
||
int dbm_delete(DBM *, datum);
|
||
int dbm_error(DBM *);
|
||
datum dbm_fetch(DBM *, datum);
|
||
datum dbm_firstkey(DBM *);
|
||
datum dbm_nextkey(DBM *);
|
||
DBM *dbm_open(const char *, int, mode_t);
|
||
int dbm_store(DBM *, datum, datum, int);
|
||
</code></pre>
|
||
<p>This API defines two types: <code>DBM</code> and <code>datum</code>.</p>
|
||
<p>The <code>DBM</code> type was called an "encapsulated" type above.
|
||
It is designed to contain internal state, and acts as an entry point for the
|
||
library's behavior.</p>
|
||
<p>It is completely opaque to the user, who cannot create a <code>DBM</code> themselves since
|
||
they don't know its size or layout. Instead, they must call <code>dbm_open</code>, and that
|
||
only gives them <em>a pointer to one</em>.</p>
|
||
<p>This means all <code>DBM</code>s are "owned" by the library in a Rust sense.
|
||
The internal state of unknown size is kept in memory controlled by the library,
|
||
not the user. The user can only manage its life cycle with <code>open</code> and <code>close</code>,
|
||
and perform operations on it with the other functions.</p>
|
||
<p>The <code>datum</code> type was called a "transactional" type above.
|
||
It is designed to facilitate the exchange of information between the library and
|
||
its user.</p>
|
||
<p>The database is designed to store "unstructured data", with no pre-defined length
|
||
or meaning. As a result, the <code>datum</code> is the C equivalent of a Rust slice: a bunch
|
||
of bytes, and a count of how many there are. The main difference is that there is
|
||
no type information, which is what <code>void</code> indicates.</p>
|
||
<p>Keep in mind that this header is written from the library's point of view.
|
||
The user likely has some type they are using, which has a known size.
|
||
But the library does not care, and by the rules of C casting, any type behind a
|
||
pointer can be cast to <code>void</code>.</p>
|
||
<p>As noted earlier, this type is <em>transparent</em> to the user. But also, this type is
|
||
<em>owned</em> by the user.
|
||
This has subtle ramifications, due to that pointer inside it.
|
||
The question is, who owns the memory that pointer points to?</p>
|
||
<p>The answer for best memory safety is, "the user".
|
||
But in cases such as retrieving a value, the user does not know how to allocate
|
||
it correctly (since they don't know how long the value is). In this case, the library
|
||
code is expected to use the heap that the user has access to -- such as the C library
|
||
<code>malloc</code> and <code>free</code> -- and then <em>transfer ownership</em> in the Rust sense.</p>
|
||
<p>This may all seem speculative, but this is what a pointer means in C.
|
||
It means the same thing as Rust: "user defined lifetime."
|
||
The user of the library needs to read the documentation in order to use it correctly.
|
||
That said, there are some decisions that have fewer or greater consequences if users
|
||
do it wrong. Minimizing those are what this best practice is about, and the key
|
||
is to <em>transfer ownership of everything that is transparent</em>.</p>
|
||
<h2 id="advantages-18"><a class="header" href="#advantages-18">Advantages</a></h2>
|
||
<p>This minimizes the number of memory safety guarantees the user must uphold to a
|
||
relatively small number:</p>
|
||
<ol>
|
||
<li>Do not call any function with a pointer not returned by <code>dbm_open</code> (invalid
|
||
access or corruption).</li>
|
||
<li>Do not call any function on a pointer after close (use after free).</li>
|
||
<li>The <code>dptr</code> on any <code>datum</code> must be <code>NULL</code>, or point to a valid slice of memory
|
||
at the advertised length.</li>
|
||
</ol>
|
||
<p>In addition, it avoids a lot of pointer provenance issues.
|
||
To understand why, let us consider an alternative in some depth: key iteration.</p>
|
||
<p>Rust is well known for its iterators.
|
||
When implementing one, the programmer makes a separate type with a bounded lifetime
|
||
to its owner, and implements the <code>Iterator</code> trait.</p>
|
||
<p>Here is how iteration would be done in Rust for <code>DBM</code>:</p>
|
||
<pre><code class="language-rust ignore">struct Dbm { ... }
|
||
|
||
impl Dbm {
|
||
/* ... */
|
||
pub fn keys<'it>(&'it self) -> DbmKeysIter<'it> { ... }
|
||
/* ... */
|
||
}
|
||
|
||
struct DbmKeysIter<'it> {
|
||
owner: &'it Dbm,
|
||
}
|
||
|
||
impl<'it> Iterator for DbmKeysIter<'it> { ... }
|
||
</code></pre>
|
||
<p>This is clean, idiomatic, and safe. thanks to Rust's guarantees.
|
||
However, consider what a straightforward API translation would look like:</p>
|
||
<pre><code class="language-rust ignore">#[no_mangle]
|
||
pub extern "C" fn dbm_iter_new(owner: *const Dbm) -> *mut DbmKeysIter {
|
||
// THIS API IS A BAD IDEA! For real applications, use object-based design instead.
|
||
}
|
||
#[no_mangle]
|
||
pub extern "C" fn dbm_iter_next(
|
||
iter: *mut DbmKeysIter,
|
||
key_out: *const datum
|
||
) -> libc::c_int {
|
||
// THIS API IS A BAD IDEA! For real applications, use object-based design instead.
|
||
}
|
||
#[no_mangle]
|
||
pub extern "C" fn dbm_iter_del(*mut DbmKeysIter) {
|
||
// THIS API IS A BAD IDEA! For real applications, use object-based design instead.
|
||
}
|
||
</code></pre>
|
||
<p>This API loses a key piece of information: the lifetime of the iterator must not
|
||
exceed the lifetime of the <code>Dbm</code> object that owns it. A user of the library could
|
||
use it in a way which causes the iterator to outlive the data it is iterating on,
|
||
resulting in reading uninitialized memory.</p>
|
||
<p>This example written in C contains a bug that will be explained afterwards:</p>
|
||
<pre><code class="language-C">int count_key_sizes(DBM *db) {
|
||
// DO NOT USE THIS FUNCTION. IT HAS A SUBTLE BUT SERIOUS BUG!
|
||
datum key;
|
||
int len = 0;
|
||
|
||
if (!dbm_iter_new(db)) {
|
||
dbm_close(db);
|
||
return -1;
|
||
}
|
||
|
||
int l;
|
||
while ((l = dbm_iter_next(owner, &key)) >= 0) { // an error is indicated by -1
|
||
free(key.dptr);
|
||
len += key.dsize;
|
||
if (l == 0) { // end of the iterator
|
||
dbm_close(owner);
|
||
}
|
||
}
|
||
if l >= 0 {
|
||
return -1;
|
||
} else {
|
||
return len;
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>This bug is a classic. Here's what happens when the iterator returns the
|
||
end-of-iteration marker:</p>
|
||
<ol>
|
||
<li>The loop condition sets <code>l</code> to zero, and enters the loop because <code>0 >= 0</code>.</li>
|
||
<li>The length is incremented, in this case by zero.</li>
|
||
<li>The if statement is true, so the database is closed. There should be a break
|
||
statement here.</li>
|
||
<li>The loop condition executes again, causing a <code>next</code> call on the closed object.</li>
|
||
</ol>
|
||
<p>The worst part about this bug?
|
||
If the Rust implementation was careful, this code will work most of the time!
|
||
If the memory for the <code>Dbm</code> object is not immediately reused, an internal check
|
||
will almost certainly fail, resulting in the iterator returning a <code>-1</code> indicating
|
||
an error. But occasionally, it will cause a segmentation fault, or even worse,
|
||
nonsensical memory corruption!</p>
|
||
<p>None of this can be avoided by Rust.
|
||
From its perspective, it put those objects on its heap, returned pointers to them,
|
||
and gave up control of their lifetimes. The C code simply must "play nice".</p>
|
||
<p>The programmer must read and understand the API documentation.
|
||
While some consider that par for the course in C, a good API design can mitigate
|
||
this risk. The POSIX API for <code>DBM</code> did this by <em>consolidating the ownership</em> of
|
||
the iterator with its parent:</p>
|
||
<pre><code class="language-C">datum dbm_firstkey(DBM *);
|
||
datum dbm_nextkey(DBM *);
|
||
</code></pre>
|
||
<p>Thus, all the lifetimes were bound together, and such unsafety was prevented.</p>
|
||
<h2 id="disadvantages-18"><a class="header" href="#disadvantages-18">Disadvantages</a></h2>
|
||
<p>However, this design choice also has a number of drawbacks, which should be
|
||
considered as well.</p>
|
||
<p>First, the API itself becomes less expressive.
|
||
With POSIX DBM, there is only one iterator per object, and every call changes
|
||
its state. This is much more restrictive than iterators in almost any language,
|
||
even though it is safe. Perhaps with other related objects, whose lifetimes are
|
||
less hierarchical, this limitation is more of a cost than the safety.</p>
|
||
<p>Second, depending on the relationships of the API's parts, significant design effort
|
||
may be involved. Many of the easier design points have other patterns associated
|
||
with them:</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="patterns/ffi/./wrappers.html">Wrapper Type Consolidation</a> groups multiple Rust types together
|
||
into an opaque "object"</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="patterns/ffi/../../idioms/ffi/errors.html">FFI Error Passing</a> explains error handling with integer
|
||
codes and sentinel return values (such as <code>NULL</code> pointers)</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="patterns/ffi/../../idioms/ffi/accepting-strings.html">Accepting Foreign Strings</a> allows accepting
|
||
strings with minimal unsafe code, and is easier to get right than
|
||
<a href="patterns/ffi/../../idioms/ffi/passing-strings.html">Passing Strings to FFI</a></p>
|
||
</li>
|
||
</ul>
|
||
<p>However, not every API can be done this way.
|
||
It is up to the best judgement of the programmer as to who their audience is.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="type-consolidation-into-wrappers"><a class="header" href="#type-consolidation-into-wrappers">Type Consolidation into Wrappers</a></h1>
|
||
<h2 id="description-28"><a class="header" href="#description-28">Description</a></h2>
|
||
<p>This pattern is designed to allow gracefully handling multiple related types,
|
||
while minimizing the surface area for memory unsafety.</p>
|
||
<p>One of the cornerstones of Rust's aliasing rules is lifetimes.
|
||
This ensures that many patterns of access between types can be memory safe,
|
||
data race safety included.</p>
|
||
<p>However, when Rust types are exported to other languages, they are usually transformed
|
||
into pointers. In Rust, a pointer means "the user manages the lifetime of the pointee."
|
||
It is their responsibility to avoid memory unsafety.</p>
|
||
<p>Some level of trust in the user code is thus required, notably around use-after-free
|
||
which Rust can do nothing about. However, some API designs place higher burdens
|
||
than others on the code written in the other language.</p>
|
||
<p>The lowest risk API is the "consolidated wrapper", where all possible interactions
|
||
with an object are folded into a "wrapper type", while keeping the Rust API clean.</p>
|
||
<h2 id="code-example-4"><a class="header" href="#code-example-4">Code Example</a></h2>
|
||
<p>To understand this, let us look at a classic example of an API to export: iteration
|
||
through a collection.</p>
|
||
<p>That API looks like this:</p>
|
||
<ol>
|
||
<li>The iterator is initialized with <code>first_key</code>.</li>
|
||
<li>Each call to <code>next_key</code> will advance the iterator.</li>
|
||
<li>Calls to <code>next_key</code> if the iterator is at the end will do nothing.</li>
|
||
<li>As noted above, the iterator is "wrapped into" the collection (unlike the native
|
||
Rust API).</li>
|
||
</ol>
|
||
<p>If the iterator implements <code>nth()</code> efficiently, then it is possible to make it
|
||
ephemeral to each function call:</p>
|
||
<pre><code class="language-rust ignore">struct MySetWrapper {
|
||
myset: MySet,
|
||
iter_next: usize,
|
||
}
|
||
|
||
impl MySetWrapper {
|
||
pub fn first_key(&mut self) -> Option<&Key> {
|
||
self.iter_next = 0;
|
||
self.next_key()
|
||
}
|
||
pub fn next_key(&mut self) -> Option<&Key> {
|
||
if let Some(next) = self.myset.keys().nth(self.iter_next) {
|
||
self.iter_next += 1;
|
||
Some(next)
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>As a result, the wrapper is simple and contains no <code>unsafe</code> code.</p>
|
||
<h2 id="advantages-19"><a class="header" href="#advantages-19">Advantages</a></h2>
|
||
<p>This makes APIs safer to use, avoiding issues with lifetimes between types.
|
||
See <a href="patterns/ffi/./export.html">Object-Based APIs</a> for more on the advantages and pitfalls
|
||
this avoids.</p>
|
||
<h2 id="disadvantages-19"><a class="header" href="#disadvantages-19">Disadvantages</a></h2>
|
||
<p>Often, wrapping types is quite difficult, and sometimes a Rust API compromise
|
||
would make things easier.</p>
|
||
<p>As an example, consider an iterator which does not efficiently implement <code>nth()</code>.
|
||
It would definitely be worth putting in special logic to make the object handle
|
||
iteration internally, or to support a different access pattern efficiently that
|
||
only the Foreign Function API will use.</p>
|
||
<h3 id="trying-to-wrap-iterators-and-failing"><a class="header" href="#trying-to-wrap-iterators-and-failing">Trying to Wrap Iterators (and Failing)</a></h3>
|
||
<p>To wrap any type of iterator into the API correctly, the wrapper would need to
|
||
do what a C version of the code would do: erase the lifetime of the iterator,
|
||
and manage it manually.</p>
|
||
<p>Suffice it to say, this is <em>incredibly</em> difficult.</p>
|
||
<p>Here is an illustration of just <em>one</em> pitfall.</p>
|
||
<p>A first version of <code>MySetWrapper</code> would look like this:</p>
|
||
<pre><code class="language-rust ignore">struct MySetWrapper {
|
||
myset: MySet,
|
||
iter_next: usize,
|
||
// created from a transmuted Box<KeysIter + 'self>
|
||
iterator: Option<NonNull<KeysIter<'static>>>,
|
||
}
|
||
</code></pre>
|
||
<p>With <code>transmute</code> being used to extend a lifetime, and a pointer to hide it,
|
||
it's ugly already. But it gets even worse: <em>any other operation can cause
|
||
Rust <code>undefined behaviour</code></em>.</p>
|
||
<p>Consider that the <code>MySet</code> in the wrapper could be manipulated by other
|
||
functions during iteration, such as storing a new value to the key it was
|
||
iterating over. The API doesn't discourage this, and in fact some similar C
|
||
libraries expect it.</p>
|
||
<p>A simple implementation of <code>myset_store</code> would be:</p>
|
||
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
||
|
||
// other module content
|
||
|
||
pub fn myset_store(
|
||
myset: *mut MySetWrapper,
|
||
key: datum,
|
||
value: datum) -> libc::c_int {
|
||
|
||
// DO NOT USE THIS CODE. IT IS UNSAFE TO DEMONSTRATE A PROLBEM.
|
||
|
||
let myset: &mut MySet = unsafe { // SAFETY: whoops, UB occurs in here!
|
||
&mut (*myset).myset
|
||
};
|
||
|
||
/* ...check and cast key and value data... */
|
||
|
||
match myset.store(casted_key, casted_value) {
|
||
Ok(_) => 0,
|
||
Err(e) => e.into()
|
||
}
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>If the iterator exists when this function is called, we have violated one of Rust's
|
||
aliasing rules. According to Rust, the mutable reference in this block must have
|
||
<em>exclusive</em> access to the object. If the iterator simply exists, it's not exclusive,
|
||
so we have <code>undefined behaviour</code>! <sup class="footnote-reference"><a href="#1">1</a></sup></p>
|
||
<p>To avoid this, we must have a way of ensuring that mutable reference really is exclusive.
|
||
That basically means clearing out the iterator's shared reference while it exists,
|
||
and then reconstructing it. In most cases, that will still be less efficient than
|
||
the C version.</p>
|
||
<p>Some may ask: how can C do this more efficiently?
|
||
The answer is, it cheats. Rust's aliasing rules are the problem, and C simply ignores
|
||
them for its pointers. In exchange, it is common to see code that is declared
|
||
in the manual as "not thread safe" under some or all circumstances. In fact,
|
||
the <a href="https://manpages.debian.org/buster/manpages/attributes.7.en.html">GNU C library</a>
|
||
has an entire lexicon dedicated to concurrent behavior!</p>
|
||
<p>Rust would rather make everything memory safe all the time, for both safety and
|
||
optimizations that C code cannot attain. Being denied access to certain shortcuts
|
||
is the price Rust programmers need to pay.</p>
|
||
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
|
||
<p>For the C programmers out there scratching their heads, the iterator need
|
||
not be read <em>during</em> this code cause the UB. The exclusivity rule also enables
|
||
compiler optimizations which may cause inconsistent observations by the iterator's
|
||
shared reference (e.g. stack spills or reordering instructions for efficiency).
|
||
These observations may happen <em>any time after</em> the mutable reference is created.</p>
|
||
</div>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="anti-patterns"><a class="header" href="#anti-patterns">Anti-patterns</a></h1>
|
||
<p>An <a href="https://en.wikipedia.org/wiki/Anti-pattern">anti-pattern</a> is a solution to
|
||
a "recurring problem that is usually ineffective and risks being highly
|
||
counterproductive". Just as valuable as knowing how to solve a problem, is
|
||
knowing how <em>not</em> to solve it. Anti-patterns give us great counter-examples to
|
||
consider relative to design patterns. Anti-patterns are not confined to code.
|
||
For example, a process can be an anti-pattern, too.</p>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="clone-to-satisfy-the-borrow-checker"><a class="header" href="#clone-to-satisfy-the-borrow-checker">Clone to satisfy the borrow checker</a></h1>
|
||
<h2 id="description-29"><a class="header" href="#description-29">Description</a></h2>
|
||
<p>The borrow checker prevents Rust users from developing otherwise unsafe code by
|
||
ensuring that either: only one mutable reference exists, or potentially many but
|
||
all immutable references exist. If the code written does not hold true to these
|
||
conditions, this anti-pattern arises when the developer resolves the compiler
|
||
error by cloning the variable.</p>
|
||
<h2 id="example-19"><a class="header" href="#example-19">Example</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>// define any variable
|
||
let mut x = 5;
|
||
|
||
// Borrow `x` -- but clone it first
|
||
let y = &mut (x.clone());
|
||
|
||
// without the x.clone() two lines prior, this line would fail on compile as
|
||
// x has been borrowed
|
||
// thanks to x.clone(), x was never borrowed, and this line will run.
|
||
println!("{}", x);
|
||
|
||
// perform some action on the borrow to prevent rust from optimizing this
|
||
//out of existence
|
||
*y += 1;
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="motivation-17"><a class="header" href="#motivation-17">Motivation</a></h2>
|
||
<p>It is tempting, particularly for beginners, to use this pattern to resolve
|
||
confusing issues with the borrow checker. However, there are serious
|
||
consequences. Using <code>.clone()</code> causes a copy of the data to be made. Any changes
|
||
between the two are not synchronized -- as if two completely separate variables
|
||
exist.</p>
|
||
<p>There are special cases -- <code>Rc<T></code> is designed to handle clones intelligently.
|
||
It internally manages exactly one copy of the data, and cloning it will only
|
||
clone the reference.</p>
|
||
<p>There is also <code>Arc<T></code> which provides shared ownership of a value of type T
|
||
that is allocated in the heap. Invoking <code>.clone()</code> on <code>Arc</code> produces a new <code>Arc</code>
|
||
instance, which points to the same allocation on the heap as the source <code>Arc</code>,
|
||
while increasing a reference count.</p>
|
||
<p>In general, clones should be deliberate, with full understanding of the
|
||
consequences. If a clone is used to make a borrow checker error disappear,
|
||
that's a good indication this anti-pattern may be in use.</p>
|
||
<p>Even though <code>.clone()</code> is an indication of a bad pattern, sometimes
|
||
<strong>it is fine to write inefficient code</strong>, in cases such as when:</p>
|
||
<ul>
|
||
<li>the developer is still new to ownership</li>
|
||
<li>the code doesn't have great speed or memory constraints
|
||
(like hackathon projects or prototypes)</li>
|
||
<li>satisfying the borrow checker is really complicated, and you prefer to
|
||
optimize readability over performance</li>
|
||
</ul>
|
||
<p>If an unnecessary clone is suspected, The <a href="https://doc.rust-lang.org/book/ownership.html">Rust Book's chapter on Ownership</a>
|
||
should be understood fully before assessing whether the clone is required or not.</p>
|
||
<p>Also be sure to always run <code>cargo clippy</code> in your project, which will detect some
|
||
cases in which <code>.clone()</code> is not necessary, like <a href="https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone">1</a>,
|
||
<a href="https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy">2</a>,
|
||
<a href="https://rust-lang.github.io/rust-clippy/master/index.html#map_clone">3</a> or <a href="https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref">4</a>.</p>
|
||
<h2 id="see-also-19"><a class="header" href="#see-also-19">See also</a></h2>
|
||
<ul>
|
||
<li><a href="anti_patterns/../idioms/mem-replace.html"><code>mem::{take(_), replace(_)}</code> to keep owned values in changed enums</a></li>
|
||
<li><a href="http://doc.rust-lang.org/std/rc/"><code>Rc<T></code> documentation, which handles .clone() intelligently</a></li>
|
||
<li><a href="https://doc.rust-lang.org/std/sync/struct.Arc.html"><code>Arc<T></code> documentation, a thread-safe reference-counting pointer</a></li>
|
||
<li><a href="https://web.archive.org/web/20210120233744/https://xion.io/post/code/rust-borrowchk-tricks.html">Tricks with ownership in Rust</a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="denywarnings"><a class="header" href="#denywarnings"><code>#![deny(warnings)]</code></a></h1>
|
||
<h2 id="description-30"><a class="header" href="#description-30">Description</a></h2>
|
||
<p>A well-intentioned crate author wants to ensure their code builds without
|
||
warnings. So they annotate their crate root with the following:</p>
|
||
<h2 id="example-20"><a class="header" href="#example-20">Example</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span>#![deny(warnings)]
|
||
|
||
<span class="boring">fn main() {
|
||
</span>// All is well.
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<h2 id="advantages-20"><a class="header" href="#advantages-20">Advantages</a></h2>
|
||
<p>It is short and will stop the build if anything is amiss.</p>
|
||
<h2 id="drawbacks"><a class="header" href="#drawbacks">Drawbacks</a></h2>
|
||
<p>By disallowing the compiler to build with warnings, a crate author opts out of
|
||
Rust's famed stability. Sometimes new features or old misfeatures need a change
|
||
in how things are done, thus lints are written that <code>warn</code> for a certain grace
|
||
period before being turned to <code>deny</code>.</p>
|
||
<p>For example, it was discovered that a type could have two <code>impl</code>s with the same
|
||
method. This was deemed a bad idea, but in order to make the transition smooth,
|
||
the <code>overlapping-inherent-impls</code> lint was introduced to give a warning to those
|
||
stumbling on this fact, before it becomes a hard error in a future release.</p>
|
||
<p>Also sometimes APIs get deprecated, so their use will emit a warning where
|
||
before there was none.</p>
|
||
<p>All this conspires to potentially break the build whenever something changes.</p>
|
||
<p>Furthermore, crates that supply additional lints (e.g. <a href="https://github.com/Manishearth/rust-clippy">rust-clippy</a>) can no
|
||
longer be used unless the annotation is removed. This is mitigated with
|
||
<a href="https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints">--cap-lints</a>. The <code>--cap-lints=warn</code> command line argument, turns all <code>deny</code>
|
||
lint errors into warnings.</p>
|
||
<h2 id="alternatives"><a class="header" href="#alternatives">Alternatives</a></h2>
|
||
<p>There are two ways of tackling this problem: First, we can decouple the build
|
||
setting from the code, and second, we can name the lints we want to deny
|
||
explicitly.</p>
|
||
<p>The following command line will build with all warnings set to <code>deny</code>:</p>
|
||
<p><code>RUSTFLAGS="-D warnings" cargo build</code></p>
|
||
<p>This can be done by any individual developer (or be set in a CI tool like
|
||
Travis, but remember that this may break the build when something changes)
|
||
without requiring a change to the code.</p>
|
||
<p>Alternatively, we can specify the lints that we want to <code>deny</code> in the code.
|
||
Here is a list of warning lints that is (hopefully) safe to deny (as of Rustc 1.48.0):</p>
|
||
<pre><code class="language-rust ignore">#[deny(bad-style,
|
||
const-err,
|
||
dead-code,
|
||
improper-ctypes,
|
||
non-shorthand-field-patterns,
|
||
no-mangle-generic-items,
|
||
overflowing-literals,
|
||
path-statements ,
|
||
patterns-in-fns-without-body,
|
||
private-in-public,
|
||
unconditional-recursion,
|
||
unused,
|
||
unused-allocation,
|
||
unused-comparisons,
|
||
unused-parens,
|
||
while-true)]
|
||
</code></pre>
|
||
<p>In addition, the following <code>allow</code>ed lints may be a good idea to <code>deny</code>:</p>
|
||
<pre><code class="language-rust ignore">#[deny(missing-debug-implementations,
|
||
missing-docs,
|
||
trivial-casts,
|
||
trivial-numeric-casts,
|
||
unused-extern-crates,
|
||
unused-import-braces,
|
||
unused-qualifications,
|
||
unused-results)]
|
||
</code></pre>
|
||
<p>Some may also want to add <code>missing-copy-implementations</code> to their list.</p>
|
||
<p>Note that we explicitly did not add the <code>deprecated</code> lint, as it is fairly
|
||
certain that there will be more deprecated APIs in the future.</p>
|
||
<h2 id="see-also-20"><a class="header" href="#see-also-20">See also</a></h2>
|
||
<ul>
|
||
<li><a href="https://rust-lang.github.io/rust-clippy/master">A collection of all clippy lints</a></li>
|
||
<li><a href="https://doc.rust-lang.org/reference/attributes.html#deprecation">deprecate attribute</a> documentation</li>
|
||
<li>Type <code>rustc -W help</code> for a list of lints on your system. Also type
|
||
<code>rustc --help</code> for a general list of options</li>
|
||
<li><a href="https://github.com/Manishearth/rust-clippy">rust-clippy</a> is a collection of lints for better Rust code</li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="deref-polymorphism"><a class="header" href="#deref-polymorphism"><code>Deref</code> polymorphism</a></h1>
|
||
<h2 id="description-31"><a class="header" href="#description-31">Description</a></h2>
|
||
<p>Abuse the <code>Deref</code> trait to emulate inheritance between structs, and thus reuse
|
||
methods.</p>
|
||
<h2 id="example-21"><a class="header" href="#example-21">Example</a></h2>
|
||
<p>Sometimes we want to emulate the following common pattern from OO languages such
|
||
as Java:</p>
|
||
<pre><code class="language-java">class Foo {
|
||
void m() { ... }
|
||
}
|
||
|
||
class Bar extends Foo {}
|
||
|
||
public static void main(String[] args) {
|
||
Bar b = new Bar();
|
||
b.m();
|
||
}
|
||
</code></pre>
|
||
<p>We can use the deref polymorphism anti-pattern to do so:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">use std::ops::Deref;
|
||
|
||
struct Foo {}
|
||
|
||
impl Foo {
|
||
fn m(&self) {
|
||
//..
|
||
}
|
||
}
|
||
|
||
struct Bar {
|
||
f: Foo,
|
||
}
|
||
|
||
impl Deref for Bar {
|
||
type Target = Foo;
|
||
fn deref(&self) -> &Foo {
|
||
&self.f
|
||
}
|
||
}
|
||
|
||
fn main() {
|
||
let b = Bar { f: Foo {} };
|
||
b.m();
|
||
}
|
||
</code></pre></pre>
|
||
<p>There is no struct inheritance in Rust. Instead we use composition and include
|
||
an instance of <code>Foo</code> in <code>Bar</code> (since the field is a value, it is stored inline,
|
||
so if there were fields, they would have the same layout in memory as the Java
|
||
version (probably, you should use <code>#[repr(C)]</code> if you want to be sure)).</p>
|
||
<p>In order to make the method call work we implement <code>Deref</code> for <code>Bar</code> with <code>Foo</code>
|
||
as the target (returning the embedded <code>Foo</code> field). That means that when we
|
||
dereference a <code>Bar</code> (for example, using <code>*</code>) then we will get a <code>Foo</code>. That is
|
||
pretty weird. Dereferencing usually gives a <code>T</code> from a reference to <code>T</code>, here we
|
||
have two unrelated types. However, since the dot operator does implicit
|
||
dereferencing, it means that the method call will search for methods on <code>Foo</code> as
|
||
well as <code>Bar</code>.</p>
|
||
<h2 id="advantages-21"><a class="header" href="#advantages-21">Advantages</a></h2>
|
||
<p>You save a little boilerplate, e.g.,</p>
|
||
<pre><code class="language-rust ignore">impl Bar {
|
||
fn m(&self) {
|
||
self.f.m()
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h2 id="disadvantages-20"><a class="header" href="#disadvantages-20">Disadvantages</a></h2>
|
||
<p>Most importantly this is a surprising idiom - future programmers reading this in
|
||
code will not expect this to happen. That's because we are abusing the <code>Deref</code>
|
||
trait rather than using it as intended (and documented, etc.). It's also because
|
||
the mechanism here is completely implicit.</p>
|
||
<p>This pattern does not introduce subtyping between <code>Foo</code> and <code>Bar</code> like
|
||
inheritance in Java or C++ does. Furthermore, traits implemented by <code>Foo</code> are
|
||
not automatically implemented for <code>Bar</code>, so this pattern interacts badly with
|
||
bounds checking and thus generic programming.</p>
|
||
<p>Using this pattern gives subtly different semantics from most OO languages with
|
||
regards to <code>self</code>. Usually it remains a reference to the sub-class, with this
|
||
pattern it will be the 'class' where the method is defined.</p>
|
||
<p>Finally, this pattern only supports single inheritance, and has no notion of
|
||
interfaces, class-based privacy, or other inheritance-related features. So, it
|
||
gives an experience that will be subtly surprising to programmers used to Java
|
||
inheritance, etc.</p>
|
||
<h2 id="discussion-15"><a class="header" href="#discussion-15">Discussion</a></h2>
|
||
<p>There is no one good alternative. Depending on the exact circumstances it might
|
||
be better to re-implement using traits or to write out the facade methods to
|
||
dispatch to <code>Foo</code> manually. We do intend to add a mechanism for inheritance
|
||
similar to this to Rust, but it is likely to be some time before it reaches
|
||
stable Rust. See these <a href="http://aturon.github.io/blog/2015/09/18/reuse/">blog</a>
|
||
<a href="http://smallcultfollowing.com/babysteps/blog/2015/10/08/virtual-structs-part-4-extended-enums-and-thin-traits/">posts</a>
|
||
and this <a href="https://github.com/rust-lang/rfcs/issues/349">RFC issue</a> for more details.</p>
|
||
<p>The <code>Deref</code> trait is designed for the implementation of custom pointer types.
|
||
The intention is that it will take a pointer-to-<code>T</code> to a <code>T</code>, not convert
|
||
between different types. It is a shame that this isn't (probably cannot be)
|
||
enforced by the trait definition.</p>
|
||
<p>Rust tries to strike a careful balance between explicit and implicit mechanisms,
|
||
favouring explicit conversions between types. Automatic dereferencing in the dot
|
||
operator is a case where the ergonomics strongly favour an implicit mechanism,
|
||
but the intention is that this is limited to degrees of indirection, not
|
||
conversion between arbitrary types.</p>
|
||
<h2 id="see-also-21"><a class="header" href="#see-also-21">See also</a></h2>
|
||
<ul>
|
||
<li><a href="anti_patterns/../idioms/deref.html">Collections are smart pointers idiom</a>.</li>
|
||
<li>Delegation crates for less boilerplate like <a href="https://crates.io/crates/delegate">delegate</a>
|
||
or <a href="https://crates.io/crates/ambassador">ambassador</a></li>
|
||
<li><a href="https://doc.rust-lang.org/std/ops/trait.Deref.html">Documentation for <code>Deref</code> trait</a>.</li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="functional-usage-of-rust"><a class="header" href="#functional-usage-of-rust">Functional Usage of Rust</a></h1>
|
||
<p>Rust is an imperative language, but it follows many
|
||
<a href="https://en.wikipedia.org/wiki/Functional_programming">functional programming</a> paradigms.</p>
|
||
<blockquote>
|
||
<p>In computer science, <em>functional programming</em> is a programming paradigm where
|
||
programs are constructed by applying and composing functions.
|
||
It is a declarative programming paradigm in which function definitions are
|
||
trees of expressions that each return a value, rather than a sequence of
|
||
imperative statements which change the state of the program.</p>
|
||
</blockquote>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="programming-paradigms"><a class="header" href="#programming-paradigms">Programming paradigms</a></h1>
|
||
<p>One of the biggest hurdles to understanding functional programs when coming
|
||
from an imperative background is the shift in thinking. Imperative programs
|
||
describe <strong>how</strong> to do something, whereas declarative programs describe
|
||
<strong>what</strong> to do. Let's sum the numbers from 1 to 10 to show this.</p>
|
||
<h2 id="imperative"><a class="header" href="#imperative">Imperative</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>let mut sum = 0;
|
||
for i in 1..11 {
|
||
sum += i;
|
||
}
|
||
println!("{}", sum);
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<p>With imperative programs, we have to play compiler to see what is happening.
|
||
Here, we start with a <code>sum</code> of <code>0</code>.
|
||
Next, we iterate through the range from 1 to 10.
|
||
Each time through the loop, we add the corresponding value in the range.
|
||
Then we print it out.</p>
|
||
<table><thead><tr><th style="text-align: center"><code>i</code></th><th style="text-align: center"><code>sum</code></th></tr></thead><tbody>
|
||
<tr><td style="text-align: center">1</td><td style="text-align: center">1</td></tr>
|
||
<tr><td style="text-align: center">2</td><td style="text-align: center">3</td></tr>
|
||
<tr><td style="text-align: center">3</td><td style="text-align: center">6</td></tr>
|
||
<tr><td style="text-align: center">4</td><td style="text-align: center">10</td></tr>
|
||
<tr><td style="text-align: center">5</td><td style="text-align: center">15</td></tr>
|
||
<tr><td style="text-align: center">6</td><td style="text-align: center">21</td></tr>
|
||
<tr><td style="text-align: center">7</td><td style="text-align: center">28</td></tr>
|
||
<tr><td style="text-align: center">8</td><td style="text-align: center">36</td></tr>
|
||
<tr><td style="text-align: center">9</td><td style="text-align: center">45</td></tr>
|
||
<tr><td style="text-align: center">10</td><td style="text-align: center">55</td></tr>
|
||
</tbody></table>
|
||
<p>This is how most of us start out programming. We learn that a program is a set
|
||
of steps.</p>
|
||
<h2 id="declarative"><a class="header" href="#declarative">Declarative</a></h2>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">
|
||
<span class="boring">#![allow(unused)]
|
||
</span><span class="boring">fn main() {
|
||
</span>println!("{}", (1..11).fold(0, |a, b| a + b));
|
||
<span class="boring">}
|
||
</span></code></pre></pre>
|
||
<p>Whoa! This is really different! What's going on here?
|
||
Remember that with declarative programs we are describing <strong>what</strong> to do,
|
||
rather than <strong>how</strong> to do it. <code>fold</code> is a function that <a href="https://en.wikipedia.org/wiki/Function_composition">composes</a>
|
||
functions. The name is a convention from Haskell.</p>
|
||
<p>Here, we are composing functions of addition (this closure: <code>|a, b| a + b</code>)
|
||
with a range from 1 to 10. The <code>0</code> is the starting point, so <code>a</code> is <code>0</code> at
|
||
first. <code>b</code> is the first element of the range, <code>1</code>. <code>0 + 1 = 1</code> is the result.
|
||
So now we <code>fold</code> again, with <code>a = 1</code>, <code>b = 2</code> and so <code>1 + 2 = 3</code> is the next
|
||
result. This process continues until we get to the last element in the range,
|
||
<code>10</code>.</p>
|
||
<table><thead><tr><th style="text-align: center"><code>a</code></th><th style="text-align: center"><code>b</code></th><th style="text-align: center">result</th></tr></thead><tbody>
|
||
<tr><td style="text-align: center">0</td><td style="text-align: center">1</td><td style="text-align: center">1</td></tr>
|
||
<tr><td style="text-align: center">1</td><td style="text-align: center">2</td><td style="text-align: center">3</td></tr>
|
||
<tr><td style="text-align: center">3</td><td style="text-align: center">3</td><td style="text-align: center">6</td></tr>
|
||
<tr><td style="text-align: center">6</td><td style="text-align: center">4</td><td style="text-align: center">10</td></tr>
|
||
<tr><td style="text-align: center">10</td><td style="text-align: center">5</td><td style="text-align: center">15</td></tr>
|
||
<tr><td style="text-align: center">15</td><td style="text-align: center">6</td><td style="text-align: center">21</td></tr>
|
||
<tr><td style="text-align: center">21</td><td style="text-align: center">7</td><td style="text-align: center">28</td></tr>
|
||
<tr><td style="text-align: center">28</td><td style="text-align: center">8</td><td style="text-align: center">36</td></tr>
|
||
<tr><td style="text-align: center">36</td><td style="text-align: center">9</td><td style="text-align: center">45</td></tr>
|
||
<tr><td style="text-align: center">45</td><td style="text-align: center">10</td><td style="text-align: center">55</td></tr>
|
||
</tbody></table>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="generics-as-type-classes"><a class="header" href="#generics-as-type-classes">Generics as Type Classes</a></h1>
|
||
<h2 id="description-32"><a class="header" href="#description-32">Description</a></h2>
|
||
<p>Rust's type system is designed more like functional languages (like Haskell)
|
||
rather than imperative languages (like Java and C++). As a result, Rust can turn
|
||
many kinds of programming problems into "static typing" problems. This is one
|
||
of the biggest wins of choosing a functional language, and is critical to many
|
||
of Rust's compile time guarantees.</p>
|
||
<p>A key part of this idea is the way generic types work. In C++ and Java, for
|
||
example, generic types are a meta-programming construct for the compiler.
|
||
<code>vector<int></code> and <code>vector<char></code> in C++ are just two different copies of the
|
||
same boilerplate code for a <code>vector</code> type (known as a <code>template</code>) with two
|
||
different types filled in.</p>
|
||
<p>In Rust, a generic type parameter creates what is known in functional languages
|
||
as a "type class constraint", and each different parameter filled in by an end
|
||
user <em>actually changes the type</em>. In other words, <code>Vec<isize></code> and <code>Vec<char></code>
|
||
<em>are two different types</em>, which are recognized as distinct by all parts of the
|
||
type system.</p>
|
||
<p>This is called <strong>monomorphization</strong>, where different types are created from
|
||
<strong>polymorphic</strong> code. This special behavior requires <code>impl</code> blocks to specify
|
||
generic parameters: different values for the generic type cause different types,
|
||
and different types can have different <code>impl</code> blocks.</p>
|
||
<p>In object-oriented languages, classes can inherit behavior from their parents.
|
||
However, this allows the attachment of not only additional behavior to
|
||
particular members of a type class, but extra behavior as well.</p>
|
||
<p>The nearest equivalent is the runtime polymorphism in Javascript and Python,
|
||
where new members can be added to objects willy-nilly by any constructor.
|
||
Unlike those languages, however, all of Rust's additional methods can be type
|
||
checked when they are used, because their generics are statically defined. That
|
||
makes them more usable while remaining safe.</p>
|
||
<h2 id="example-22"><a class="header" href="#example-22">Example</a></h2>
|
||
<p>Suppose you are designing a storage server for a series of lab machines.
|
||
Because of the software involved, there are two different protocols you need
|
||
to support: BOOTP (for PXE network boot), and NFS (for remote mount storage).</p>
|
||
<p>Your goal is to have one program, written in Rust, which can handle both of
|
||
them. It will have protocol handlers and listen for both kinds of requests. The
|
||
main application logic will then allow a lab administrator to configure storage
|
||
and security controls for the actual files.</p>
|
||
<p>The requests from machines in the lab for files contain the same basic
|
||
information, no matter what protocol they came from: an authentication method,
|
||
and a file name to retrieve. A straightforward implementation would look
|
||
something like this:</p>
|
||
<pre><code class="language-rust ignore">
|
||
enum AuthInfo {
|
||
Nfs(crate::nfs::AuthInfo),
|
||
Bootp(crate::bootp::AuthInfo),
|
||
}
|
||
|
||
struct FileDownloadRequest {
|
||
file_name: PathBuf,
|
||
authentication: AuthInfo,
|
||
}
|
||
</code></pre>
|
||
<p>This design might work well enough. But now suppose you needed to support
|
||
adding metadata that was <em>protocol specific</em>. For example, with NFS, you
|
||
wanted to determine what their mount point was in order to enforce additional
|
||
security rules.</p>
|
||
<p>The way the current struct is designed leaves the protocol decision until
|
||
runtime. That means any method that applies to one protocol and not the other
|
||
requires the programmer to do a runtime check.</p>
|
||
<p>Here is how getting an NFS mount point would look:</p>
|
||
<pre><code class="language-rust ignore">struct FileDownloadRequest {
|
||
file_name: PathBuf,
|
||
authentication: AuthInfo,
|
||
mount_point: Option<PathBuf>,
|
||
}
|
||
|
||
impl FileDownloadRequest {
|
||
// ... other methods ...
|
||
|
||
/// Gets an NFS mount point if this is an NFS request. Otherwise,
|
||
/// return None.
|
||
pub fn mount_point(&self) -> Option<&Path> {
|
||
self.mount_point.as_ref()
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>Every caller of <code>mount_point()</code> must check for <code>None</code> and write code to handle
|
||
it. This is true even if they know only NFS requests are ever used in a given
|
||
code path!</p>
|
||
<p>It would be far more optimal to cause a compile-time error if the different
|
||
request types were confused. After all, the entire path of the user's code,
|
||
including what functions from the library they use, will know whether a request
|
||
is an NFS request or a BOOTP request.</p>
|
||
<p>In Rust, this is actually possible! The solution is to <em>add a generic type</em> in
|
||
order to split the API.</p>
|
||
<p>Here is what that looks like:</p>
|
||
<pre><pre class="playground"><code class="language-rust edition2018">use std::path::{Path, PathBuf};
|
||
|
||
mod nfs {
|
||
#[derive(Clone)]
|
||
pub(crate) struct AuthInfo(String); // NFS session management omitted
|
||
}
|
||
|
||
mod bootp {
|
||
pub(crate) struct AuthInfo(); // no authentication in bootp
|
||
}
|
||
|
||
// private module, lest outside users invent their own protocol kinds!
|
||
mod proto_trait {
|
||
use std::path::{Path, PathBuf};
|
||
use super::{bootp, nfs};
|
||
|
||
pub(crate) trait ProtoKind {
|
||
type AuthInfo;
|
||
fn auth_info(&self) -> Self::AuthInfo;
|
||
}
|
||
|
||
pub struct Nfs {
|
||
auth: nfs::AuthInfo,
|
||
mount_point: PathBuf,
|
||
}
|
||
|
||
impl Nfs {
|
||
pub(crate) fn mount_point(&self) -> &Path {
|
||
&self.mount_point
|
||
}
|
||
}
|
||
|
||
impl ProtoKind for Nfs {
|
||
type AuthInfo = nfs::AuthInfo;
|
||
fn auth_info(&self) -> Self::AuthInfo {
|
||
self.auth.clone()
|
||
}
|
||
}
|
||
|
||
pub struct Bootp(); // no additional metadata
|
||
|
||
impl ProtoKind for Bootp {
|
||
type AuthInfo = bootp::AuthInfo;
|
||
fn auth_info(&self) -> Self::AuthInfo {
|
||
bootp::AuthInfo()
|
||
}
|
||
}
|
||
}
|
||
|
||
use proto_trait::ProtoKind; // keep internal to prevent impls
|
||
pub use proto_trait::{Nfs, Bootp}; // re-export so callers can see them
|
||
|
||
struct FileDownloadRequest<P: ProtoKind> {
|
||
file_name: PathBuf,
|
||
protocol: P,
|
||
}
|
||
|
||
// all common API parts go into a generic impl block
|
||
impl<P: ProtoKind> FileDownloadRequest<P> {
|
||
fn file_path(&self) -> &Path {
|
||
&self.file_name
|
||
}
|
||
|
||
fn auth_info(&self) -> P::AuthInfo {
|
||
self.protocol.auth_info()
|
||
}
|
||
}
|
||
|
||
// all protocol-specific impls go into their own block
|
||
impl FileDownloadRequest<Nfs> {
|
||
fn mount_point(&self) -> &Path {
|
||
self.protocol.mount_point()
|
||
}
|
||
}
|
||
|
||
fn main() {
|
||
// your code here
|
||
}
|
||
</code></pre></pre>
|
||
<p>With this approach, if the user were to make a mistake and use the wrong
|
||
type;</p>
|
||
<pre><code class="language-rust ignore">fn main() {
|
||
let mut socket = crate::bootp::listen()?;
|
||
while let Some(request) = socket.next_request()? {
|
||
match request.mount_point().as_ref()
|
||
"/secure" => socket.send("Access denied"),
|
||
_ => {} // continue on...
|
||
}
|
||
// Rest of the code here
|
||
}
|
||
}
|
||
</code></pre>
|
||
<p>They would get a syntax error. The type <code>FileDownloadRequest<Bootp></code> does not
|
||
implement <code>mount_point()</code>, only the type <code>FileDownloadRequest<Nfs></code> does. And
|
||
that is created by the NFS module, not the BOOTP module of course!</p>
|
||
<h2 id="advantages-22"><a class="header" href="#advantages-22">Advantages</a></h2>
|
||
<p>First, it allows fields that are common to multiple states to be de-duplicated.
|
||
By making the non-shared fields generic, they are implemented once.</p>
|
||
<p>Second, it makes the <code>impl</code> blocks easier to read, because they are broken down
|
||
by state. Methods common to all states are typed once in one block, and methods
|
||
unique to one state are in a separate block.</p>
|
||
<p>Both of these mean there are fewer lines of code, and they are better organized.</p>
|
||
<h2 id="disadvantages-21"><a class="header" href="#disadvantages-21">Disadvantages</a></h2>
|
||
<p>This currently increases the size of the binary, due to the way monomorphization
|
||
is implemented in the compiler. Hopefully the implementation will be able to
|
||
improve in the future.</p>
|
||
<h2 id="alternatives-1"><a class="header" href="#alternatives-1">Alternatives</a></h2>
|
||
<ul>
|
||
<li>
|
||
<p>If a type seems to need a "split API" due to construction or partial
|
||
initialization, consider the
|
||
<a href="functional/../patterns/creational/builder.html">Builder Pattern</a> instead.</p>
|
||
</li>
|
||
<li>
|
||
<p>If the API between types does not change -- only the behavior does -- then
|
||
the <a href="functional/../patterns/behavioural/strategy.html">Strategy Pattern</a> is better used
|
||
instead.</p>
|
||
</li>
|
||
</ul>
|
||
<h2 id="see-also-22"><a class="header" href="#see-also-22">See also</a></h2>
|
||
<p>This pattern is used throughout the standard library:</p>
|
||
<ul>
|
||
<li><code>Vec<u8></code> can be cast from a String, unlike every other type of <code>Vec<T></code>.<sup class="footnote-reference"><a href="#1">1</a></sup></li>
|
||
<li>They can also be cast into a binary heap, but only if they contain a type
|
||
that implements the <code>Ord</code> trait.<sup class="footnote-reference"><a href="#2">2</a></sup></li>
|
||
<li>The <code>to_string</code> method was specialized for <code>Cow</code> only of type <code>str</code>.<sup class="footnote-reference"><a href="#3">3</a></sup></li>
|
||
</ul>
|
||
<p>It is also used by several popular crates to allow API flexibility:</p>
|
||
<ul>
|
||
<li>
|
||
<p>The <code>embedded-hal</code> ecosystem used for embedded devices makes extensive use of
|
||
this pattern. For example, it allows statically verifying the configuration of
|
||
device registers used to control embedded pins. When a pin is put into a mode,
|
||
it returns a <code>Pin<MODE></code> struct, whose generic determines the functions
|
||
usable in that mode, which are not on the <code>Pin</code> itself. <sup class="footnote-reference"><a href="#4">4</a></sup></p>
|
||
</li>
|
||
<li>
|
||
<p>The <code>hyper</code> HTTP client library uses this to expose rich APIs for different
|
||
pluggable requests. Clients with different connectors have different methods
|
||
on them as well as different trait implementations, while a core set of
|
||
methods apply to any connector. <sup class="footnote-reference"><a href="#5">5</a></sup></p>
|
||
</li>
|
||
<li>
|
||
<p>The "type state" pattern -- where an object gains and loses API based on an
|
||
internal state or invariant -- is implemented in Rust using the same basic
|
||
concept, and a slightly different technique. <sup class="footnote-reference"><a href="#6">6</a></sup></p>
|
||
</li>
|
||
</ul>
|
||
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
|
||
<p>See: <a href="https://doc.rust-lang.org/stable/src/std/ffi/c_str.rs.html#799-801">impl From<CString> for Vec<u8></a></p>
|
||
</div>
|
||
<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup>
|
||
<p>See: <a href="https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354">impl<T> From<Vec<T, Global>> for BinaryHeap<T></a></p>
|
||
</div>
|
||
<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup>
|
||
<p>See: <a href="https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240">impl<'_> ToString for Cow<'_, str></a></p>
|
||
</div>
|
||
<div class="footnote-definition" id="4"><sup class="footnote-definition-label">4</sup>
|
||
<p>Example:
|
||
<a href="https://docs.rs/stm32f30x-hal/0.1.0/stm32f30x_hal/gpio/gpioa/struct.PA0.html">https://docs.rs/stm32f30x-hal/0.1.0/stm32f30x_hal/gpio/gpioa/struct.PA0.html</a></p>
|
||
</div>
|
||
<div class="footnote-definition" id="5"><sup class="footnote-definition-label">5</sup>
|
||
<p>See:
|
||
<a href="https://docs.rs/hyper/0.14.5/hyper/client/struct.Client.html">https://docs.rs/hyper/0.14.5/hyper/client/struct.Client.html</a></p>
|
||
</div>
|
||
<div class="footnote-definition" id="6"><sup class="footnote-definition-label">6</sup>
|
||
<p>See:
|
||
<a href="https://web.archive.org/web/20210325065112/https://www.novatec-gmbh.de/en/blog/the-case-for-the-typestate-pattern-the-typestate-pattern-itself/">The Case for the Type State Pattern</a>
|
||
and
|
||
<a href="https://web.archive.org/web/20210328164854/https://rustype.github.io/notes/notes/rust-typestate-series/rust-typestate-index">Rusty Typestate Series (an extensive thesis)</a></p>
|
||
</div>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="additional-resources"><a class="header" href="#additional-resources">Additional resources</a></h1>
|
||
<p>A collection of complementary helpful content</p>
|
||
<h2 id="talks"><a class="header" href="#talks">Talks</a></h2>
|
||
<ul>
|
||
<li><a href="https://www.youtube.com/watch?v=Pm_oO0N5B9k">Design Patterns in Rust</a> by
|
||
Nicholas Cameron at the PDRust (2016)</li>
|
||
<li><a href="https://www.youtube.com/watch?v=0zOg8_B71gE">Writing Idiomatic Libraries in Rust</a>
|
||
by Pascal Hertleif at RustFest (2017)</li>
|
||
<li><a href="https://www.youtube.com/watch?v=vqavdUGKeb4">Rust Programming Techniques</a> by
|
||
Nicholas Cameron at LinuxConfAu (2018)</li>
|
||
</ul>
|
||
<h2 id="books-online"><a class="header" href="#books-online">Books (Online)</a></h2>
|
||
<ul>
|
||
<li><a href="https://rust-lang.github.io/api-guidelines">The Rust API Guidelines</a></li>
|
||
</ul>
|
||
<div style="break-before: page; page-break-before: always;"></div><h1 id="design-principles"><a class="header" href="#design-principles">Design principles</a></h1>
|
||
<h2 id="a-brief-overview-over-common-design-principles"><a class="header" href="#a-brief-overview-over-common-design-principles">A brief overview over common design principles</a></h2>
|
||
<hr />
|
||
<h2 id="solid"><a class="header" href="#solid"><a href="https://en.wikipedia.org/wiki/SOLID">SOLID</a></a></h2>
|
||
<ul>
|
||
<li><a href="https://en.wikipedia.org/wiki/Single-responsibility_principle">Single Responsibility Principle (SRP)</a>:
|
||
A class should only have a single responsibility, that is, only changes to
|
||
one part of the software's specification should be able to affect the
|
||
specification of the class.</li>
|
||
<li><a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle">Open/Closed Principle (OCP)</a>:
|
||
"Software entities ... should be open for extension, but closed for
|
||
modification."</li>
|
||
<li><a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle">Liskov Substitution Principle (LSP)</a>:
|
||
"Objects in a program should be replaceable with instances of their subtypes
|
||
without altering the correctness of that program."</li>
|
||
<li><a href="https://en.wikipedia.org/wiki/Interface_segregation_principle">Interface Segregation Principle (ISP)</a>:
|
||
"Many client-specific interfaces are better than one general-purpose
|
||
interface."</li>
|
||
<li><a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion Principle (DIP)</a>:
|
||
One should "depend upon abstractions, [not] concretions."</li>
|
||
</ul>
|
||
<h2 id="dry-dont-repeat-yourself"><a class="header" href="#dry-dont-repeat-yourself"><a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY (Don’t Repeat Yourself)</a></a></h2>
|
||
<p>"Every piece of knowledge must have a single, unambiguous, authoritative
|
||
representation within a system"</p>
|
||
<h2 id="kiss-principle"><a class="header" href="#kiss-principle"><a href="https://en.wikipedia.org/wiki/KISS_principle">KISS principle</a></a></h2>
|
||
<p>most systems work best if they are kept simple rather than made complicated;
|
||
therefore, simplicity should be a key goal in design, and unnecessary
|
||
complexity should be avoided</p>
|
||
<h2 id="law-of-demeter-lod"><a class="header" href="#law-of-demeter-lod"><a href="https://en.wikipedia.org/wiki/Law_of_Demeter">Law of Demeter (LoD)</a></a></h2>
|
||
<p>a given object should assume as little as possible about the structure or
|
||
properties of anything else (including its subcomponents), in accordance with
|
||
the principle of "information hiding"</p>
|
||
<h2 id="design-by-contract-dbc"><a class="header" href="#design-by-contract-dbc"><a href="https://en.wikipedia.org/wiki/Design_by_contract">Design by contract (DbC)</a></a></h2>
|
||
<p>software designers should define formal, precise and verifiable interface
|
||
specifications for software components, which extend the ordinary definition of
|
||
abstract data types with preconditions, postconditions and invariants</p>
|
||
<h2 id="encapsulation"><a class="header" href="#encapsulation"><a href="https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)">Encapsulation</a></a></h2>
|
||
<p>bundling of data with the methods that operate on that data, or the restricting
|
||
of direct access to some of an object's components. Encapsulation is used to
|
||
hide the values or state of a structured data object inside a class, preventing
|
||
unauthorized parties' direct access to them.</p>
|
||
<h2 id="command-query-separationcqs"><a class="header" href="#command-query-separationcqs"><a href="https://en.wikipedia.org/wiki/Command%E2%80%93query_separation">Command-Query-Separation(CQS)</a></a></h2>
|
||
<p>“Functions should not produce abstract side effects...only commands
|
||
(procedures) will be permitted to produce side effects.” - Bertrand Meyer:
|
||
Object-Oriented Software Construction</p>
|
||
<h2 id="principle-of-least-astonishment-pola"><a class="header" href="#principle-of-least-astonishment-pola"><a href="https://en.wikipedia.org/wiki/Principle_of_least_astonishment">Principle of least astonishment (POLA)</a></a></h2>
|
||
<p>a component of a system should behave in a way that most users will expect it
|
||
to behave. The behavior should not astonish or surprise users</p>
|
||
<h2 id="linguistic-modular-units"><a class="header" href="#linguistic-modular-units">Linguistic-Modular-Units</a></h2>
|
||
<p>“Modules must correspond to syntactic units in the language used.” - Bertrand
|
||
Meyer: Object-Oriented Software Construction</p>
|
||
<h2 id="self-documentation"><a class="header" href="#self-documentation">Self-Documentation</a></h2>
|
||
<p>“The designer of a module should strive to make all information about the
|
||
module part of the module itself.” - Bertrand Meyer: Object-Oriented Software
|
||
Construction</p>
|
||
<h2 id="uniform-access"><a class="header" href="#uniform-access">Uniform-Access</a></h2>
|
||
<p>“All services offered by a module should be available through a uniform
|
||
notation, which does not betray whether they are implemented through storage or
|
||
through computation.” - Bertrand Meyer: Object-Oriented Software Construction</p>
|
||
<h2 id="single-choice"><a class="header" href="#single-choice">Single-Choice</a></h2>
|
||
<p>“Whenever a software system must support a set of alternatives, one and only
|
||
one module in the system should know their exhaustive list.” - Bertrand Meyer:
|
||
Object-Oriented Software Construction</p>
|
||
<h2 id="persistence-closure"><a class="header" href="#persistence-closure">Persistence-Closure</a></h2>
|
||
<p>“Whenever a storage mechanism stores an object, it must store with it the
|
||
dependents of that object. Whenever a retrieval mechanism retrieves a
|
||
previously stored object, it must also retrieve any dependent of that object
|
||
that has not yet been retrieved.” - Bertrand Meyer: Object-Oriented Software
|
||
Construction</p>
|
||
|
||
</main>
|
||
|
||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||
<!-- Mobile navigation buttons -->
|
||
<div style="clear: both"></div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||
</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 -->
|
||
<script type="text/javascript">
|
||
window.addEventListener('load', function() {
|
||
window.setTimeout(window.print, 100);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|