diff --git a/ch04-02-references-and-borrowing.html b/ch04-02-references-and-borrowing.html index 028022721b..76590a35c7 100644 --- a/ch04-02-references-and-borrowing.html +++ b/ch04-02-references-and-borrowing.html @@ -217,7 +217,7 @@
The macro vec!
creates a vector with the elements between the brackets. The vector v
has type Vec<i32>
. The syntax <i32>
means the elements of the vector have type i32
.
One important implementation detail is that v
allocates a heap array of a certain capacity. We can peek into Vec
’s internals and see this detail for ourselves:
@@ -278,7 +278,7 @@Note: click the binocular icon in the top right of the diagram to toggle this detailed view in any runtime diagram.
Recall the Pointer Safety Principle: data should not be aliased and mutated. The goal of these permissions is to ensure that data cannot be mutated if it is aliased. Creating a reference to data (“borrowing” it) causes that data to be temporarily read-only until the reference is no longer in use.
Rust uses these permissions in its borrow checker. The borrow checker looks for potentially unsafe operations involving references. Let’s return to the unsafe program we saw earlier, where push
invalidates a reference. This time we’ll add another aspect to the permissions diagram:
Any time a place is used, Rust expects that place to have certain permissions depending on the operation. For example, the borrow &v[2]
requires that v
is readable. Therefore the R permission is shown between the operation &
and the place v
. The letter is filled-in because v
has the read permission at that line.
By contrast, the mutating operation v.push(4)
requires that v
is readable and writable. Both R and W are shown. However, v
does not have write permissions (it is borrowed by num
). So the letter W is hollow, indicating that the write permission is expected but v
does not have it.
If you try to compile this program, then the Rust compiler will return the following error:
@@ -306,7 +306,7 @@v
becomes temporarily unusable, so effectively not an alias.
The second observation is what makes mutable references useful. v[2]
can be mutated through *num
. For example, *num += 1
mutates v[2]
. Note that *num
has the W permission, but num
does not. num
refers to the mutable reference itself, e.g. num
cannot be reassigned to a different mutable reference.
Mutable references can also be temporarily “downgraded” to read-only references. For example:
- +@@ -317,13 +317,13 @@Note: when permission changes are not relevant to an example, we will hide them. You can view hidden steps by clicking “»”, and you can view hidden permissions within a step by clicking “● ● ●”.
The W permission on x
is returned to x
after the lifetime of y
has ended, like we have seen before.
In the previous examples, a lifetime has been a contiguous region of code. However, once we introduce control flow, this is not necessarily the case. For example, here is a function that capitalizes the first character in a vector of ASCII characters:
- +The variable c
has a different lifetime in each branch of the if-statement. In the then-block, c
is used in the expression c.to_ascii_uppercase()
. Therefore *v
does not regain the W permission until after that line.
However, in the else-block, c
is not used. *v
immediately regains the W permission on entry to the else-block.
As a part of the Pointer Safety Principle, the borrow checker enforces that data must outlive any references to it. Rust enforces this property in two ways. The first way deals with references that are created and dropped within the scope of a single function. For example, say we tried to drop a string while holding a reference to it:
- +To catch these kinds of errors, Rust uses the permissions we’ve already discussed. The borrow &s
removes the O permission from s
. However, drop
expects the O permission, leading to a permission mismatch.
The key idea is that in this example, Rust knows how long s_ref
lives. But Rust needs a different enforcement mechanism when it doesn’t know how long a reference lives. Specifically, when references are either input to a function, or output from a function. For example, here is a safe function that returns a reference to the first element in a vector:
To see the F permission in another context, say you tried to return a reference to a variable on the stack like this:
- +This program is unsafe because the reference &s
will be invalidated when return_a_string
returns. And Rust will reject this program with a similar missing lifetime specifier
error. Now you can understand that error means that s_ref
is missing the appropriate flow permissions.
Another common issue is trying to mutate read-only data, or trying to drop data behind a reference. For example, let’s say we tried to write a function stringify_name_with_title
. This function is supposed to create a person’s full name from a vector of name parts, including an extra title.
This program is rejected by the borrow checker because name
is an immutable reference, but name.push(..)
requires the W permission. This program is unsafe because push
could invalidate other references to name
outside of stringify_name_with_title
, like this:
In this example, a reference first
to name[0]
is created before calling stringify_name_with_title
. The function name.push(..)
reallocates the contents of name
, which invalidates first
, causing the println
to read deallocated memory.
Another unsafe operation is using a reference to heap data that gets deallocated by another alias. For example, here’s a function that gets a reference to the largest string in a vector, and then uses it while mutating the vector:
- +@@ -278,7 +278,7 @@Note: this example uses iterators and closures to succinctly find a reference to the largest string. We will discuss those features in later chapters, and for now we will provide an intuitive sense of how the features work here.
dst
to not overlap with a mutation to dst
.
A common confusion for Rust learners happens when copying data out of a collection, like a vector. For example, here’s a safe program that copies a number out of a vector:
- +The dereference operation *n_ref
expects just the R permission, which the path *n_ref
has. But what happens if we change the type of elements in the vector from i32
to String
? Then it turns out we no longer have the necessary permissions:
The first program will compile, but the second program will not compile. Rust gives the following error message:
@@ -336,10 +336,10 @@The above examples are cases where a program is unsafe. Rust may also reject safe programs. One common issue is that Rust tries to track permissions at a fine-grained level. However, Rust may conflate two different places as the same place.
Let’s first look at an example of fine-grained permission tracking that passes the borrow checker. This program shows how you can borrow one field of a tuple, and write to a different field of the same tuple:
- +The statement let first = &name.0
borrows name.0
. This borrow removes WO permissions from name.0
. It also removes WO permissions from name
. (For example, one could not pass name
to a function that takes as input a value of type (String, String)
.) But name.1
still retains the W permission, so doing name.1.push_str(...)
is a valid operation.
However, Rust can lose track of exactly which places are borrowed. For example, let’s say we refactor the expression &name.0
into a function get_first
. Notice how after calling get_first(&name)
, Rust now removes the W permission on name.1
:
Now we can’t do name.1.push_str(..)
! Rust will return this error:
error[E0502]: cannot borrow `name.1` as mutable because it is also borrowed as immutable
--> test.rs:11:5
@@ -361,7 +361,7 @@ let idx = a_complex_function();
let x = &mut a[idx];
What is the value of idx
? Rust isn’t going to guess, so it assumes idx
could be anything. For example, let’s say we try to read from one array index while writing to a different one:
However, Rust will reject this program because a
gave its read permission to x
. The compiler’s error message says the same thing:
error[E0502]: cannot borrow `a[_]` as immutable because it is also borrowed as mutable
--> test.rs:4:9
diff --git a/ch04-04-slices.html b/ch04-04-slices.html
index 81fe870000..b6d7099a4c 100644
--- a/ch04-04-slices.html
+++ b/ch04-04-slices.html
@@ -245,7 +245,7 @@ The Slice Type<
will still be valid in the future. Consider the program in Listing 4-8 that
uses the first_word
function from Listing 4-7.
Filename: src/main.rs
-
+
This program compiles without any errors, as s
retains write permissions
@@ -355,7 +355,7 @@
Filename: src/main.rs
-
+
You can see that calling first_word
now removes the write permission from s
,
which prevents us from calling s.clear()
. Here’s the compiler error:
$ cargo run
diff --git a/ch04-05-ownership-recap.html b/ch04-05-ownership-recap.html
index bb21d7b2ed..dbc43db3cf 100644
--- a/ch04-05-ownership-recap.html
+++ b/ch04-05-ownership-recap.html
@@ -255,9 +255,9 @@ Own
If you want to review slices, re-read Chapter 4.4.
Ownership at Compile-time
Rust tracks R (read), W (write), and O (own) permissions on each variable. Rust requires that a variable has appropriate permissions to perform a given operation. As a basic example, if a variable is not declared as let mut
, then it is missing the W permission and cannot be mutated:
-
+
A variable’s permissions can be changed if it is moved or borrowed. A move of a variable with a non-copyable type (like Box<T>
or String
) requires the RO permissions, and the move eliminates all permissions on the variable. That rule prevents the use of moved variables:
-
+
If you want to review how moves work, re-read Chapter 4.1.
Borrowing a variable (creating a reference to it) temporarily removes some of the variable’s permissions. An immutable borrow creates an immutable reference, and also disables the borrowed data from being mutated or moved. For example, printing an immutable reference is ok:
@@ -266,11 +266,11 @@
And moving data out of the reference is not ok:
-
+
A mutable borrow creates a mutable reference, which disables the borrowed data from being read, written, or moved. For example, mutating a mutable reference is ok:
-
+
But accessing the mutably borrowed data is not ok:
-
+
If you want to review permissions and references, re-read Chapter 4.2.
Connecting Ownership between Compile-time and Runtime
Rust’s permissions are designed to prevent undefined behavior. For example, one kind of undefined behavior is a use-after-free where freed memory is read or written. Immutable borrows remove the W permission to avoid use-after-free, like in this case:
@@ -281,7 +281,7 @@ The Rest of Ownership
As we introduce additional features like structs, enums, and traits, those features will have specific interactions with ownership. This chapter provides the essential foundation for understanding those interactions — the concepts of memory, pointers, undefined behavior, and permissions will help us talk about the more advanced parts of Rust in future chapters.
And don’t forget to take the quizzes if you want to check your understanding!
- +In fact, the original invention of ownership types wasn’t about memory safety at all. It was about preventing leaks of mutable references to data structure internals in Java-like languages. If you’re curious to learn more about the history of ownership types, check out the paper “Ownership Types for Flexible Alias Protection” (Clarke et al. 1998).
Similar to our discussion in “Different Tuple Fields”, Rust’s borrow checker will track ownership permissions
at both the struct-level and field-level. For example, if we borrow a field x
of a Point
structure, then both p
and p.x
temporarily lose their permissions (but not p.y
):
As a result, if we try and use p
while p.x
is mutably borrowed like this:
Then the compiler will reject our program with the following error:
error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
--> test.rs:10:17
diff --git a/ch05-03-method-syntax.html b/ch05-03-method-syntax.html
index babaee2757..be7a7e006d 100644
--- a/ch05-03-method-syntax.html
+++ b/ch05-03-method-syntax.html
@@ -542,10 +542,10 @@
+
Moves with self
Calling a method that expects self
will move the input struct (unless the struct implements Copy
). For example, we cannot use a Rectangle
after passing it to max
:
-
+
Once we call rect.max(..)
, we move rect
and so lose all permissions on it. Trying to compile this program would give us the following error:
error[E0382]: borrow of moved value: `rect`
--> test.rs:33:16
@@ -559,7 +559,7 @@ Moves with
A similar situation arises if we try to call a self
method on a reference. For instance, say we tried to make a method set_to_max
that assigns self
to the output of self.max(..)
:
-
+
Then we can see that self
is missing O permissions in the operation self.max(..)
. Rust therefore rejects this program with the following error:
error[E0507]: cannot move out of `*self` which is behind a mutable reference
--> test.rs:23:17
diff --git a/ch06-02-match.html b/ch06-02-match.html
index 599b3d17bb..d138933fb6 100644
--- a/ch06-02-match.html
+++ b/ch06-02-match.html
@@ -507,12 +507,12 @@ How Matches Interact with Ownership
If an enum contains non-copyable data like a String, then you should be careful with whether a match will move or borrow that data. For example, this program using an Option<String>
will compile:
-
+
But if we replace the placeholder in Some(_)
with a variable name, like Some(s)
, then the program will NOT compile:
-
+
opt
is a plain enum — its type is Option<String>
and not a reference like &Option<String>
. Therefore a match on opt
will move non-ignored fields like s
. Notice how opt
loses read and own permission sooner in the second program compared to the first. After the match expression, the data within opt
has been moved, so it is illegal to read opt
in the println
.
If we want to peek into opt
without moving its contents, the idiomatic solution is to match on a reference:
-
+
Rust will “push down” the reference from the outer enum, &Option<String>
, to the inner field, &String
. Therefore s
has type &String
, and opt
can be used after the match. To better understand this “pushing down” mechanism, see the section about binding modes in the Rust Reference.
diff --git a/ch13-01-closures.html b/ch13-01-closures.html
index 5033e522a0..1c8c89ed1f 100644
--- a/ch13-01-closures.html
+++ b/ch13-01-closures.html
@@ -746,7 +746,7 @@ }
These changes say: s_ref
is a string reference that lives for 'a
. Adding + 'a
to the return type’s trait bounds indicates that the closure must live no longer than 'a
. Therefore Rust deduces this function is now safe. If we try to use it unsafely like before:
Rust recognizes that as long as make_a_cloner
is in use, s_own
cannot be dropped. This is reflected in the permissions: s_own
loses the O permission after calling make_a_cloner
. Consequently, Rust rejects this program with the following error:
error[E0505]: cannot move out of `s_own` because it is borrowed
--> test.rs:9:6
diff --git a/experiment-intro.html b/experiment-intro.html
index 64d194dbec..fe534bf120 100644
--- a/experiment-intro.html
+++ b/experiment-intro.html
@@ -173,6 +173,11 @@ 2. Highlighting
3. …and more!
The book’s content may change as you go through the experiment. We will update this page as we add new features. Here’s the changelog:
+- September 26, 2024
+
+- Chris Krycho’s chapter on async Rust has been added, along with new quiz questions.
+
+
- February 16, 2023
- A new chapter on ownership has replaced the previous Chapter 4.
@@ -199,7 +204,19 @@ 3. …and more!
Interested in participating in other experiments about making Rust easier to learn? Please sign up here: https://forms.gle/U3jEUkb2fGXykp1DA
-4. Acknowledgments
+4. Publications
+Thus far, this experiment has led to two open-access publications. Check them out if you’re interested to see the academic research behind this book:
+
+-
+
Profiling Programming Language Learning
+Will Crichton and Shriram Krishnamurthi. OOPSLA 2024. (Distinguished Paper!)
+
+-
+
A Grounded Conceptual Model for Ownership Types in Rust
+Will Crichton, Gavin Gray, and Shriram Krishnamurthi. OOPSLA 2023.
+
+
+5. Acknowledgments
Niko Matsakis and Amazon Web Services provided funding for this experiment. Carol Nichols and the Rust Foundation helped publicize the experiment. TRPL is the product of many people’s hard work before we started this experiment.
diff --git a/index.html b/index.html
index 64d194dbec..fe534bf120 100644
--- a/index.html
+++ b/index.html
@@ -173,6 +173,11 @@ 2. Highlighting
3. …and more!
The book’s content may change as you go through the experiment. We will update this page as we add new features. Here’s the changelog:
+- September 26, 2024
+
+- Chris Krycho’s chapter on async Rust has been added, along with new quiz questions.
+
+
- February 16, 2023
- A new chapter on ownership has replaced the previous Chapter 4.
@@ -199,7 +204,19 @@ 3. …and more!
Interested in participating in other experiments about making Rust easier to learn? Please sign up here: https://forms.gle/U3jEUkb2fGXykp1DA
-4. Acknowledgments
+4. Publications
+Thus far, this experiment has led to two open-access publications. Check them out if you’re interested to see the academic research behind this book:
+
+-
+
Profiling Programming Language Learning
+Will Crichton and Shriram Krishnamurthi. OOPSLA 2024. (Distinguished Paper!)
+
+-
+
A Grounded Conceptual Model for Ownership Types in Rust
+Will Crichton, Gavin Gray, and Shriram Krishnamurthi. OOPSLA 2023.
+
+
+5. Acknowledgments
Niko Matsakis and Amazon Web Services provided funding for this experiment. Carol Nichols and the Rust Foundation helped publicize the experiment. TRPL is the product of many people’s hard work before we started this experiment.
diff --git a/js-extensions/packages/telemetry/dist/index.js b/js-extensions/packages/telemetry/dist/index.js
index b4251e2510..e613263ac6 100644
--- a/js-extensions/packages/telemetry/dist/index.js
+++ b/js-extensions/packages/telemetry/dist/index.js
@@ -1,2 +1,2 @@
"use strict";(()=>{var Mr=Object.create;var xe=Object.defineProperty;var kr=Object.getOwnPropertyDescriptor;var Vr=Object.getOwnPropertyNames;var Jr=Object.getPrototypeOf,Wr=Object.prototype.hasOwnProperty;var l=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);var zr=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Vr(e))!Wr.call(r,n)&&n!==t&&xe(r,n,{get:()=>e[n],enumerable:!(i=kr(e,n))||i.enumerable});return r};var Xr=(r,e,t)=>(t=r!=null?Mr(Jr(r)):{},zr(e||!r||!r.__esModule?xe(t,"default",{value:r,enumerable:!0}):t,r));var X=l((nn,we)=>{"use strict";we.exports=function(e,t){return function(){for(var n=new Array(arguments.length),s=0;s{"use strict";var $r=X(),Y=Object.prototype.toString,K=function(r){return function(e){var t=Y.call(e);return r[t]||(r[t]=t.slice(8,-1).toLowerCase())}}(Object.create(null));function A(r){return r=r.toLowerCase(),function(t){return K(t)===r}}function G(r){return Array.isArray(r)}function L(r){return typeof r>"u"}function Yr(r){return r!==null&&!L(r)&&r.constructor!==null&&!L(r.constructor)&&typeof r.constructor.isBuffer=="function"&&r.constructor.isBuffer(r)}var be=A("ArrayBuffer");function Kr(r){var e;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?e=ArrayBuffer.isView(r):e=r&&r.buffer&&be(r.buffer),e}function Gr(r){return typeof r=="string"}function Qr(r){return typeof r=="number"}function Oe(r){return r!==null&&typeof r=="object"}function B(r){if(K(r)!=="object")return!1;var e=Object.getPrototypeOf(r);return e===null||e===Object.prototype}var Zr=A("Date"),et=A("File"),rt=A("Blob"),tt=A("FileList");function Q(r){return Y.call(r)==="[object Function]"}function nt(r){return Oe(r)&&Q(r.pipe)}function it(r){var e="[object FormData]";return r&&(typeof FormData=="function"&&r instanceof FormData||Y.call(r)===e||Q(r.toString)&&r.toString()===e)}var st=A("URLSearchParams");function ot(r){return r.trim?r.trim():r.replace(/^\s+|\s+$/g,"")}function at(){return typeof navigator<"u"&&(navigator.product==="ReactNative"||navigator.product==="NativeScript"||navigator.product==="NS")?!1:typeof window<"u"&&typeof document<"u"}function Z(r,e){if(!(r===null||typeof r>"u"))if(typeof r!="object"&&(r=[r]),G(r))for(var t=0,i=r.length;t0;)s=i[n],o[s]||(e[s]=r[s],o[s]=!0);r=Object.getPrototypeOf(r)}while(r&&(!t||t(r,e))&&r!==Object.prototype);return e}function dt(r,e,t){r=String(r),(t===void 0||t>r.length)&&(t=r.length),t-=e.length;var i=r.indexOf(e,t);return i!==-1&&i===t}function pt(r){if(!r)return null;var e=r.length;if(L(e))return null;for(var t=new Array(e);e-- >0;)t[e]=r[e];return t}var ht=function(r){return function(e){return r&&e instanceof r}}(typeof Uint8Array<"u"&&Object.getPrototypeOf(Uint8Array));qe.exports={isArray:G,isArrayBuffer:be,isBuffer:Yr,isFormData:it,isArrayBufferView:Kr,isString:Gr,isNumber:Qr,isObject:Oe,isPlainObject:B,isUndefined:L,isDate:Zr,isFile:et,isBlob:rt,isFunction:Q,isStream:nt,isURLSearchParams:st,isStandardBrowserEnv:at,forEach:Z,merge:$,extend:ut,trim:ot,stripBOM:ft,inherits:lt,toFlatObject:ct,kindOf:K,kindOfTest:A,endsWith:dt,toArray:pt,isTypedArray:ht,isFileList:tt}});var ee=l((on,Se)=>{"use strict";var T=d();function Ae(r){return encodeURIComponent(r).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}Se.exports=function(e,t,i){if(!t)return e;var n;if(i)n=i(t);else if(T.isURLSearchParams(t))n=t.toString();else{var s=[];T.forEach(t,function(f,h){f===null||typeof f>"u"||(T.isArray(f)?h=h+"[]":f=[f],T.forEach(f,function(c){T.isDate(c)?c=c.toISOString():T.isObject(c)&&(c=JSON.stringify(c)),s.push(Ae(h)+"="+Ae(c))}))}),n=s.join("&")}if(n){var o=e.indexOf("#");o!==-1&&(e=e.slice(0,o)),e+=(e.indexOf("?")===-1?"?":"&")+n}return e}});var Te=l((an,ge)=>{"use strict";var mt=d();function I(){this.handlers=[]}I.prototype.use=function(e,t,i){return this.handlers.push({fulfilled:e,rejected:t,synchronous:i?i.synchronous:!1,runWhen:i?i.runWhen:null}),this.handlers.length-1};I.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)};I.prototype.forEach=function(e){mt.forEach(this.handlers,function(i){i!==null&&e(i)})};ge.exports=I});var Ne=l((un,Ce)=>{"use strict";var vt=d();Ce.exports=function(e,t){vt.forEach(e,function(n,s){s!==t&&s.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[s])})}});var S=l((fn,Ue)=>{"use strict";var _e=d();function C(r,e,t,i,n){Error.call(this),this.message=r,this.name="AxiosError",e&&(this.code=e),t&&(this.config=t),i&&(this.request=i),n&&(this.response=n)}_e.inherits(C,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code,status:this.response&&this.response.status?this.response.status:null}}});var Pe=C.prototype,De={};["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED"].forEach(function(r){De[r]={value:r}});Object.defineProperties(C,De);Object.defineProperty(Pe,"isAxiosError",{value:!0});C.from=function(r,e,t,i,n,s){var o=Object.create(Pe);return _e.toFlatObject(r,o,function(f){return f!==Error.prototype}),C.call(o,r.message,e,t,i,n),o.name=r.name,s&&Object.assign(o,s),o};Ue.exports=C});var re=l((ln,Be)=>{"use strict";Be.exports={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1}});var te=l((cn,Le)=>{"use strict";var w=d();function Et(r,e){e=e||new FormData;var t=[];function i(s){return s===null?"":w.isDate(s)?s.toISOString():w.isArrayBuffer(s)||w.isTypedArray(s)?typeof Blob=="function"?new Blob([s]):Buffer.from(s):s}function n(s,o){if(w.isPlainObject(s)||w.isArray(s)){if(t.indexOf(s)!==-1)throw Error("Circular reference detected in "+o);t.push(s),w.forEach(s,function(f,h){if(!w.isUndefined(f)){var a=o?o+"."+h:h,c;if(f&&!o&&typeof f=="object"){if(w.endsWith(h,"{}"))f=JSON.stringify(f);else if(w.endsWith(h,"[]")&&(c=w.toArray(f))){c.forEach(function(y){!w.isUndefined(y)&&e.append(a,i(y))});return}}n(f,a)}}),t.pop()}else e.append(o,i(s))}return n(r),e}Le.exports=Et});var Fe=l((dn,Ie)=>{"use strict";var ne=S();Ie.exports=function(e,t,i){var n=i.config.validateStatus;!i.status||!n||n(i.status)?e(i):t(new ne("Request failed with status code "+i.status,[ne.ERR_BAD_REQUEST,ne.ERR_BAD_RESPONSE][Math.floor(i.status/100)-4],i.config,i.request,i))}});var He=l((pn,je)=>{"use strict";var F=d();je.exports=F.isStandardBrowserEnv()?function(){return{write:function(t,i,n,s,o,u){var f=[];f.push(t+"="+encodeURIComponent(i)),F.isNumber(n)&&f.push("expires="+new Date(n).toGMTString()),F.isString(s)&&f.push("path="+s),F.isString(o)&&f.push("domain="+o),u===!0&&f.push("secure"),document.cookie=f.join("; ")},read:function(t){var i=document.cookie.match(new RegExp("(^|;\\s*)("+t+")=([^;]*)"));return i?decodeURIComponent(i[3]):null},remove:function(t){this.write(t,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()});var ke=l((hn,Me)=>{"use strict";Me.exports=function(e){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}});var Je=l((mn,Ve)=>{"use strict";Ve.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}});var ie=l((vn,We)=>{"use strict";var yt=ke(),Rt=Je();We.exports=function(e,t){return e&&!yt(t)?Rt(e,t):t}});var Xe=l((En,ze)=>{"use strict";var se=d(),xt=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];ze.exports=function(e){var t={},i,n,s;return e&&se.forEach(e.split(`
-`),function(u){if(s=u.indexOf(":"),i=se.trim(u.substr(0,s)).toLowerCase(),n=se.trim(u.substr(s+1)),i){if(t[i]&&xt.indexOf(i)>=0)return;i==="set-cookie"?t[i]=(t[i]?t[i]:[]).concat([n]):t[i]=t[i]?t[i]+", "+n:n}}),t}});var Ke=l((yn,Ye)=>{"use strict";var $e=d();Ye.exports=$e.isStandardBrowserEnv()?function(){var e=/(msie|trident)/i.test(navigator.userAgent),t=document.createElement("a"),i;function n(s){var o=s;return e&&(t.setAttribute("href",o),o=t.href),t.setAttribute("href",o),{href:t.href,protocol:t.protocol?t.protocol.replace(/:$/,""):"",host:t.host,search:t.search?t.search.replace(/^\?/,""):"",hash:t.hash?t.hash.replace(/^#/,""):"",hostname:t.hostname,port:t.port,pathname:t.pathname.charAt(0)==="/"?t.pathname:"/"+t.pathname}}return i=n(window.location.href),function(o){var u=$e.isString(o)?n(o):o;return u.protocol===i.protocol&&u.host===i.host}}():function(){return function(){return!0}}()});var D=l((Rn,Qe)=>{"use strict";var oe=S(),wt=d();function Ge(r){oe.call(this,r??"canceled",oe.ERR_CANCELED),this.name="CanceledError"}wt.inherits(Ge,oe,{__CANCEL__:!0});Qe.exports=Ge});var er=l((xn,Ze)=>{"use strict";Ze.exports=function(e){var t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}});var ae=l((wn,rr)=>{"use strict";var U=d(),bt=Fe(),Ot=He(),qt=ee(),At=ie(),St=Xe(),gt=Ke(),Tt=re(),b=S(),Ct=D(),Nt=er();rr.exports=function(e){return new Promise(function(i,n){var s=e.data,o=e.headers,u=e.responseType,f;function h(){e.cancelToken&&e.cancelToken.unsubscribe(f),e.signal&&e.signal.removeEventListener("abort",f)}U.isFormData(s)&&U.isStandardBrowserEnv()&&delete o["Content-Type"];var a=new XMLHttpRequest;if(e.auth){var c=e.auth.username||"",y=e.auth.password?unescape(encodeURIComponent(e.auth.password)):"";o.Authorization="Basic "+btoa(c+":"+y)}var v=At(e.baseURL,e.url);a.open(e.method.toUpperCase(),qt(v,e.params,e.paramsSerializer),!0),a.timeout=e.timeout;function ye(){if(!!a){var x="getAllResponseHeaders"in a?St(a.getAllResponseHeaders()):null,g=!u||u==="text"||u==="json"?a.responseText:a.response,q={data:g,status:a.status,statusText:a.statusText,headers:x,config:e,request:a};bt(function(z){i(z),h()},function(z){n(z),h()},q),a=null}}if("onloadend"in a?a.onloadend=ye:a.onreadystatechange=function(){!a||a.readyState!==4||a.status===0&&!(a.responseURL&&a.responseURL.indexOf("file:")===0)||setTimeout(ye)},a.onabort=function(){!a||(n(new b("Request aborted",b.ECONNABORTED,e,a)),a=null)},a.onerror=function(){n(new b("Network Error",b.ERR_NETWORK,e,a,a)),a=null},a.ontimeout=function(){var g=e.timeout?"timeout of "+e.timeout+"ms exceeded":"timeout exceeded",q=e.transitional||Tt;e.timeoutErrorMessage&&(g=e.timeoutErrorMessage),n(new b(g,q.clarifyTimeoutError?b.ETIMEDOUT:b.ECONNABORTED,e,a)),a=null},U.isStandardBrowserEnv()){var Re=(e.withCredentials||gt(v))&&e.xsrfCookieName?Ot.read(e.xsrfCookieName):void 0;Re&&(o[e.xsrfHeaderName]=Re)}"setRequestHeader"in a&&U.forEach(o,function(g,q){typeof s>"u"&&q.toLowerCase()==="content-type"?delete o[q]:a.setRequestHeader(q,g)}),U.isUndefined(e.withCredentials)||(a.withCredentials=!!e.withCredentials),u&&u!=="json"&&(a.responseType=e.responseType),typeof e.onDownloadProgress=="function"&&a.addEventListener("progress",e.onDownloadProgress),typeof e.onUploadProgress=="function"&&a.upload&&a.upload.addEventListener("progress",e.onUploadProgress),(e.cancelToken||e.signal)&&(f=function(x){!a||(n(!x||x&&x.type?new Ct:x),a.abort(),a=null)},e.cancelToken&&e.cancelToken.subscribe(f),e.signal&&(e.signal.aborted?f():e.signal.addEventListener("abort",f))),s||(s=null);var W=Nt(v);if(W&&["http","https","file"].indexOf(W)===-1){n(new b("Unsupported protocol "+W+":",b.ERR_BAD_REQUEST,e));return}a.send(s)})}});var nr=l((bn,tr)=>{tr.exports=null});var H=l((On,ar)=>{"use strict";var p=d(),ir=Ne(),sr=S(),_t=re(),Pt=te(),Dt={"Content-Type":"application/x-www-form-urlencoded"};function or(r,e){!p.isUndefined(r)&&p.isUndefined(r["Content-Type"])&&(r["Content-Type"]=e)}function Ut(){var r;return typeof XMLHttpRequest<"u"?r=ae():typeof process<"u"&&Object.prototype.toString.call(process)==="[object process]"&&(r=ae()),r}function Bt(r,e,t){if(p.isString(r))try{return(e||JSON.parse)(r),p.trim(r)}catch(i){if(i.name!=="SyntaxError")throw i}return(t||JSON.stringify)(r)}var j={transitional:_t,adapter:Ut(),transformRequest:[function(e,t){if(ir(t,"Accept"),ir(t,"Content-Type"),p.isFormData(e)||p.isArrayBuffer(e)||p.isBuffer(e)||p.isStream(e)||p.isFile(e)||p.isBlob(e))return e;if(p.isArrayBufferView(e))return e.buffer;if(p.isURLSearchParams(e))return or(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString();var i=p.isObject(e),n=t&&t["Content-Type"],s;if((s=p.isFileList(e))||i&&n==="multipart/form-data"){var o=this.env&&this.env.FormData;return Pt(s?{"files[]":e}:e,o&&new o)}else if(i||n==="application/json")return or(t,"application/json"),Bt(e);return e}],transformResponse:[function(e){var t=this.transitional||j.transitional,i=t&&t.silentJSONParsing,n=t&&t.forcedJSONParsing,s=!i&&this.responseType==="json";if(s||n&&p.isString(e)&&e.length)try{return JSON.parse(e)}catch(o){if(s)throw o.name==="SyntaxError"?sr.from(o,sr.ERR_BAD_RESPONSE,this,null,this.response):o}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:nr()},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};p.forEach(["delete","get","head"],function(e){j.headers[e]={}});p.forEach(["post","put","patch"],function(e){j.headers[e]=p.merge(Dt)});ar.exports=j});var fr=l((qn,ur)=>{"use strict";var Lt=d(),It=H();ur.exports=function(e,t,i){var n=this||It;return Lt.forEach(i,function(o){e=o.call(n,e,t)}),e}});var ue=l((An,lr)=>{"use strict";lr.exports=function(e){return!!(e&&e.__CANCEL__)}});var pr=l((Sn,dr)=>{"use strict";var cr=d(),fe=fr(),Ft=ue(),jt=H(),Ht=D();function le(r){if(r.cancelToken&&r.cancelToken.throwIfRequested(),r.signal&&r.signal.aborted)throw new Ht}dr.exports=function(e){le(e),e.headers=e.headers||{},e.data=fe.call(e,e.data,e.headers,e.transformRequest),e.headers=cr.merge(e.headers.common||{},e.headers[e.method]||{},e.headers),cr.forEach(["delete","get","head","post","put","patch","common"],function(n){delete e.headers[n]});var t=e.adapter||jt.adapter;return t(e).then(function(n){return le(e),n.data=fe.call(e,n.data,n.headers,e.transformResponse),n},function(n){return Ft(n)||(le(e),n&&n.response&&(n.response.data=fe.call(e,n.response.data,n.response.headers,e.transformResponse))),Promise.reject(n)})}});var ce=l((gn,hr)=>{"use strict";var R=d();hr.exports=function(e,t){t=t||{};var i={};function n(a,c){return R.isPlainObject(a)&&R.isPlainObject(c)?R.merge(a,c):R.isPlainObject(c)?R.merge({},c):R.isArray(c)?c.slice():c}function s(a){if(R.isUndefined(t[a])){if(!R.isUndefined(e[a]))return n(void 0,e[a])}else return n(e[a],t[a])}function o(a){if(!R.isUndefined(t[a]))return n(void 0,t[a])}function u(a){if(R.isUndefined(t[a])){if(!R.isUndefined(e[a]))return n(void 0,e[a])}else return n(void 0,t[a])}function f(a){if(a in t)return n(e[a],t[a]);if(a in e)return n(void 0,e[a])}var h={url:o,method:o,data:o,baseURL:u,transformRequest:u,transformResponse:u,paramsSerializer:u,timeout:u,timeoutMessage:u,withCredentials:u,adapter:u,responseType:u,xsrfCookieName:u,xsrfHeaderName:u,onUploadProgress:u,onDownloadProgress:u,decompress:u,maxContentLength:u,maxBodyLength:u,beforeRedirect:u,transport:u,httpAgent:u,httpsAgent:u,cancelToken:u,socketPath:u,responseEncoding:u,validateStatus:f};return R.forEach(Object.keys(e).concat(Object.keys(t)),function(c){var y=h[c]||s,v=y(c);R.isUndefined(v)&&y!==f||(i[c]=v)}),i}});var de=l((Tn,mr)=>{mr.exports={version:"0.27.2"}});var yr=l((Cn,Er)=>{"use strict";var Mt=de().version,O=S(),pe={};["object","boolean","number","function","string","symbol"].forEach(function(r,e){pe[r]=function(i){return typeof i===r||"a"+(e<1?"n ":" ")+r}});var vr={};pe.transitional=function(e,t,i){function n(s,o){return"[Axios v"+Mt+"] Transitional option '"+s+"'"+o+(i?". "+i:"")}return function(s,o,u){if(e===!1)throw new O(n(o," has been removed"+(t?" in "+t:"")),O.ERR_DEPRECATED);return t&&!vr[o]&&(vr[o]=!0,console.warn(n(o," has been deprecated since v"+t+" and will be removed in the near future"))),e?e(s,o,u):!0}};function kt(r,e,t){if(typeof r!="object")throw new O("options must be an object",O.ERR_BAD_OPTION_VALUE);for(var i=Object.keys(r),n=i.length;n-- >0;){var s=i[n],o=e[s];if(o){var u=r[s],f=u===void 0||o(u,s,r);if(f!==!0)throw new O("option "+s+" must be "+f,O.ERR_BAD_OPTION_VALUE);continue}if(t!==!0)throw new O("Unknown option "+s,O.ERR_BAD_OPTION)}}Er.exports={assertOptions:kt,validators:pe}});var qr=l((Nn,Or)=>{"use strict";var wr=d(),Vt=ee(),Rr=Te(),xr=pr(),M=ce(),Jt=ie(),br=yr(),N=br.validators;function _(r){this.defaults=r,this.interceptors={request:new Rr,response:new Rr}}_.prototype.request=function(e,t){typeof e=="string"?(t=t||{},t.url=e):t=e||{},t=M(this.defaults,t),t.method?t.method=t.method.toLowerCase():this.defaults.method?t.method=this.defaults.method.toLowerCase():t.method="get";var i=t.transitional;i!==void 0&&br.assertOptions(i,{silentJSONParsing:N.transitional(N.boolean),forcedJSONParsing:N.transitional(N.boolean),clarifyTimeoutError:N.transitional(N.boolean)},!1);var n=[],s=!0;this.interceptors.request.forEach(function(v){typeof v.runWhen=="function"&&v.runWhen(t)===!1||(s=s&&v.synchronous,n.unshift(v.fulfilled,v.rejected))});var o=[];this.interceptors.response.forEach(function(v){o.push(v.fulfilled,v.rejected)});var u;if(!s){var f=[xr,void 0];for(Array.prototype.unshift.apply(f,n),f=f.concat(o),u=Promise.resolve(t);f.length;)u=u.then(f.shift(),f.shift());return u}for(var h=t;n.length;){var a=n.shift(),c=n.shift();try{h=a(h)}catch(y){c(y);break}}try{u=xr(h)}catch(y){return Promise.reject(y)}for(;o.length;)u=u.then(o.shift(),o.shift());return u};_.prototype.getUri=function(e){e=M(this.defaults,e);var t=Jt(e.baseURL,e.url);return Vt(t,e.params,e.paramsSerializer)};wr.forEach(["delete","get","head","options"],function(e){_.prototype[e]=function(t,i){return this.request(M(i||{},{method:e,url:t,data:(i||{}).data}))}});wr.forEach(["post","put","patch"],function(e){function t(i){return function(s,o,u){return this.request(M(u||{},{method:e,headers:i?{"Content-Type":"multipart/form-data"}:{},url:s,data:o}))}}_.prototype[e]=t(),_.prototype[e+"Form"]=t(!0)});Or.exports=_});var Sr=l((_n,Ar)=>{"use strict";var Wt=D();function P(r){if(typeof r!="function")throw new TypeError("executor must be a function.");var e;this.promise=new Promise(function(n){e=n});var t=this;this.promise.then(function(i){if(!!t._listeners){var n,s=t._listeners.length;for(n=0;n{"use strict";gr.exports=function(e){return function(i){return e.apply(null,i)}}});var Nr=l((Dn,Cr)=>{"use strict";var zt=d();Cr.exports=function(e){return zt.isObject(e)&&e.isAxiosError===!0}});var Dr=l((Un,he)=>{"use strict";var _r=d(),Xt=X(),k=qr(),$t=ce(),Yt=H();function Pr(r){var e=new k(r),t=Xt(k.prototype.request,e);return _r.extend(t,k.prototype,e),_r.extend(t,e),t.create=function(n){return Pr($t(r,n))},t}var E=Pr(Yt);E.Axios=k;E.CanceledError=D();E.CancelToken=Sr();E.isCancel=ue();E.VERSION=de().version;E.toFormData=te();E.AxiosError=S();E.Cancel=E.CanceledError;E.all=function(e){return Promise.all(e)};E.spread=Tr();E.isAxiosError=Nr();he.exports=E;he.exports.default=E});var Br=l((Bn,Ur)=>{Ur.exports=Dr()});var jr=Xr(Br());var V,Kt=new Uint8Array(16);function me(){if(!V&&(V=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||typeof msCrypto<"u"&&typeof msCrypto.getRandomValues=="function"&&msCrypto.getRandomValues.bind(msCrypto),!V))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return V(Kt)}var Lr=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function Gt(r){return typeof r=="string"&&Lr.test(r)}var Ir=Gt;var m=[];for(J=0;J<256;++J)m.push((J+256).toString(16).substr(1));var J;function Qt(r){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0,t=(m[r[e+0]]+m[r[e+1]]+m[r[e+2]]+m[r[e+3]]+"-"+m[r[e+4]]+m[r[e+5]]+"-"+m[r[e+6]]+m[r[e+7]]+"-"+m[r[e+8]]+m[r[e+9]]+"-"+m[r[e+10]]+m[r[e+11]]+m[r[e+12]]+m[r[e+13]]+m[r[e+14]]+m[r[e+15]]).toLowerCase();if(!Ir(t))throw TypeError("Stringified UUID is invalid");return t}var Fr=Qt;function Zt(r,e,t){r=r||{};var i=r.random||(r.rng||me)();if(i[6]=i[6]&15|64,i[8]=i[8]&63|128,e){t=t||0;for(var n=0;n<16;++n)e[t+n]=i[n];return e}return Fr(i)}var ve=Zt;function rn(){let r="__telemetry_session";return localStorage.getItem(r)===null&&localStorage.setItem(r,ve()),localStorage.getItem(r)}var Ee=class{constructor(e,t,i){this.url=e;this.commitHash=t;this.branch=i;this.sessionId=rn()}log(e,t){if(!(this.branch=="main"||this.branch=="master")||window.location.hostname=="localhost"&&!this.url.includes("localhost"))return;let n={sessionId:this.sessionId,commitHash:this.commitHash,timestamp:new Date().getTime(),payload:t},s=this.url+"/"+e;console.debug(`Logging to ${s}:`,n),jr.default.post(s,n)}};typeof window<"u"&&(window.telemetry=new Ee("https://rust-book.willcrichton.net/logs","1f05d9bfb4e1af2170d159fdfeac695fe243fe9d","main"));})();
+`),function(u){if(s=u.indexOf(":"),i=se.trim(u.substr(0,s)).toLowerCase(),n=se.trim(u.substr(s+1)),i){if(t[i]&&xt.indexOf(i)>=0)return;i==="set-cookie"?t[i]=(t[i]?t[i]:[]).concat([n]):t[i]=t[i]?t[i]+", "+n:n}}),t}});var Ke=l((yn,Ye)=>{"use strict";var $e=d();Ye.exports=$e.isStandardBrowserEnv()?function(){var e=/(msie|trident)/i.test(navigator.userAgent),t=document.createElement("a"),i;function n(s){var o=s;return e&&(t.setAttribute("href",o),o=t.href),t.setAttribute("href",o),{href:t.href,protocol:t.protocol?t.protocol.replace(/:$/,""):"",host:t.host,search:t.search?t.search.replace(/^\?/,""):"",hash:t.hash?t.hash.replace(/^#/,""):"",hostname:t.hostname,port:t.port,pathname:t.pathname.charAt(0)==="/"?t.pathname:"/"+t.pathname}}return i=n(window.location.href),function(o){var u=$e.isString(o)?n(o):o;return u.protocol===i.protocol&&u.host===i.host}}():function(){return function(){return!0}}()});var D=l((Rn,Qe)=>{"use strict";var oe=S(),wt=d();function Ge(r){oe.call(this,r??"canceled",oe.ERR_CANCELED),this.name="CanceledError"}wt.inherits(Ge,oe,{__CANCEL__:!0});Qe.exports=Ge});var er=l((xn,Ze)=>{"use strict";Ze.exports=function(e){var t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}});var ae=l((wn,rr)=>{"use strict";var U=d(),bt=Fe(),Ot=He(),qt=ee(),At=ie(),St=Xe(),gt=Ke(),Tt=re(),b=S(),Ct=D(),Nt=er();rr.exports=function(e){return new Promise(function(i,n){var s=e.data,o=e.headers,u=e.responseType,f;function h(){e.cancelToken&&e.cancelToken.unsubscribe(f),e.signal&&e.signal.removeEventListener("abort",f)}U.isFormData(s)&&U.isStandardBrowserEnv()&&delete o["Content-Type"];var a=new XMLHttpRequest;if(e.auth){var c=e.auth.username||"",y=e.auth.password?unescape(encodeURIComponent(e.auth.password)):"";o.Authorization="Basic "+btoa(c+":"+y)}var v=At(e.baseURL,e.url);a.open(e.method.toUpperCase(),qt(v,e.params,e.paramsSerializer),!0),a.timeout=e.timeout;function ye(){if(!!a){var x="getAllResponseHeaders"in a?St(a.getAllResponseHeaders()):null,g=!u||u==="text"||u==="json"?a.responseText:a.response,q={data:g,status:a.status,statusText:a.statusText,headers:x,config:e,request:a};bt(function(z){i(z),h()},function(z){n(z),h()},q),a=null}}if("onloadend"in a?a.onloadend=ye:a.onreadystatechange=function(){!a||a.readyState!==4||a.status===0&&!(a.responseURL&&a.responseURL.indexOf("file:")===0)||setTimeout(ye)},a.onabort=function(){!a||(n(new b("Request aborted",b.ECONNABORTED,e,a)),a=null)},a.onerror=function(){n(new b("Network Error",b.ERR_NETWORK,e,a,a)),a=null},a.ontimeout=function(){var g=e.timeout?"timeout of "+e.timeout+"ms exceeded":"timeout exceeded",q=e.transitional||Tt;e.timeoutErrorMessage&&(g=e.timeoutErrorMessage),n(new b(g,q.clarifyTimeoutError?b.ETIMEDOUT:b.ECONNABORTED,e,a)),a=null},U.isStandardBrowserEnv()){var Re=(e.withCredentials||gt(v))&&e.xsrfCookieName?Ot.read(e.xsrfCookieName):void 0;Re&&(o[e.xsrfHeaderName]=Re)}"setRequestHeader"in a&&U.forEach(o,function(g,q){typeof s>"u"&&q.toLowerCase()==="content-type"?delete o[q]:a.setRequestHeader(q,g)}),U.isUndefined(e.withCredentials)||(a.withCredentials=!!e.withCredentials),u&&u!=="json"&&(a.responseType=e.responseType),typeof e.onDownloadProgress=="function"&&a.addEventListener("progress",e.onDownloadProgress),typeof e.onUploadProgress=="function"&&a.upload&&a.upload.addEventListener("progress",e.onUploadProgress),(e.cancelToken||e.signal)&&(f=function(x){!a||(n(!x||x&&x.type?new Ct:x),a.abort(),a=null)},e.cancelToken&&e.cancelToken.subscribe(f),e.signal&&(e.signal.aborted?f():e.signal.addEventListener("abort",f))),s||(s=null);var W=Nt(v);if(W&&["http","https","file"].indexOf(W)===-1){n(new b("Unsupported protocol "+W+":",b.ERR_BAD_REQUEST,e));return}a.send(s)})}});var nr=l((bn,tr)=>{tr.exports=null});var H=l((On,ar)=>{"use strict";var p=d(),ir=Ne(),sr=S(),_t=re(),Pt=te(),Dt={"Content-Type":"application/x-www-form-urlencoded"};function or(r,e){!p.isUndefined(r)&&p.isUndefined(r["Content-Type"])&&(r["Content-Type"]=e)}function Ut(){var r;return typeof XMLHttpRequest<"u"?r=ae():typeof process<"u"&&Object.prototype.toString.call(process)==="[object process]"&&(r=ae()),r}function Bt(r,e,t){if(p.isString(r))try{return(e||JSON.parse)(r),p.trim(r)}catch(i){if(i.name!=="SyntaxError")throw i}return(t||JSON.stringify)(r)}var j={transitional:_t,adapter:Ut(),transformRequest:[function(e,t){if(ir(t,"Accept"),ir(t,"Content-Type"),p.isFormData(e)||p.isArrayBuffer(e)||p.isBuffer(e)||p.isStream(e)||p.isFile(e)||p.isBlob(e))return e;if(p.isArrayBufferView(e))return e.buffer;if(p.isURLSearchParams(e))return or(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString();var i=p.isObject(e),n=t&&t["Content-Type"],s;if((s=p.isFileList(e))||i&&n==="multipart/form-data"){var o=this.env&&this.env.FormData;return Pt(s?{"files[]":e}:e,o&&new o)}else if(i||n==="application/json")return or(t,"application/json"),Bt(e);return e}],transformResponse:[function(e){var t=this.transitional||j.transitional,i=t&&t.silentJSONParsing,n=t&&t.forcedJSONParsing,s=!i&&this.responseType==="json";if(s||n&&p.isString(e)&&e.length)try{return JSON.parse(e)}catch(o){if(s)throw o.name==="SyntaxError"?sr.from(o,sr.ERR_BAD_RESPONSE,this,null,this.response):o}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:nr()},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};p.forEach(["delete","get","head"],function(e){j.headers[e]={}});p.forEach(["post","put","patch"],function(e){j.headers[e]=p.merge(Dt)});ar.exports=j});var fr=l((qn,ur)=>{"use strict";var Lt=d(),It=H();ur.exports=function(e,t,i){var n=this||It;return Lt.forEach(i,function(o){e=o.call(n,e,t)}),e}});var ue=l((An,lr)=>{"use strict";lr.exports=function(e){return!!(e&&e.__CANCEL__)}});var pr=l((Sn,dr)=>{"use strict";var cr=d(),fe=fr(),Ft=ue(),jt=H(),Ht=D();function le(r){if(r.cancelToken&&r.cancelToken.throwIfRequested(),r.signal&&r.signal.aborted)throw new Ht}dr.exports=function(e){le(e),e.headers=e.headers||{},e.data=fe.call(e,e.data,e.headers,e.transformRequest),e.headers=cr.merge(e.headers.common||{},e.headers[e.method]||{},e.headers),cr.forEach(["delete","get","head","post","put","patch","common"],function(n){delete e.headers[n]});var t=e.adapter||jt.adapter;return t(e).then(function(n){return le(e),n.data=fe.call(e,n.data,n.headers,e.transformResponse),n},function(n){return Ft(n)||(le(e),n&&n.response&&(n.response.data=fe.call(e,n.response.data,n.response.headers,e.transformResponse))),Promise.reject(n)})}});var ce=l((gn,hr)=>{"use strict";var R=d();hr.exports=function(e,t){t=t||{};var i={};function n(a,c){return R.isPlainObject(a)&&R.isPlainObject(c)?R.merge(a,c):R.isPlainObject(c)?R.merge({},c):R.isArray(c)?c.slice():c}function s(a){if(R.isUndefined(t[a])){if(!R.isUndefined(e[a]))return n(void 0,e[a])}else return n(e[a],t[a])}function o(a){if(!R.isUndefined(t[a]))return n(void 0,t[a])}function u(a){if(R.isUndefined(t[a])){if(!R.isUndefined(e[a]))return n(void 0,e[a])}else return n(void 0,t[a])}function f(a){if(a in t)return n(e[a],t[a]);if(a in e)return n(void 0,e[a])}var h={url:o,method:o,data:o,baseURL:u,transformRequest:u,transformResponse:u,paramsSerializer:u,timeout:u,timeoutMessage:u,withCredentials:u,adapter:u,responseType:u,xsrfCookieName:u,xsrfHeaderName:u,onUploadProgress:u,onDownloadProgress:u,decompress:u,maxContentLength:u,maxBodyLength:u,beforeRedirect:u,transport:u,httpAgent:u,httpsAgent:u,cancelToken:u,socketPath:u,responseEncoding:u,validateStatus:f};return R.forEach(Object.keys(e).concat(Object.keys(t)),function(c){var y=h[c]||s,v=y(c);R.isUndefined(v)&&y!==f||(i[c]=v)}),i}});var de=l((Tn,mr)=>{mr.exports={version:"0.27.2"}});var yr=l((Cn,Er)=>{"use strict";var Mt=de().version,O=S(),pe={};["object","boolean","number","function","string","symbol"].forEach(function(r,e){pe[r]=function(i){return typeof i===r||"a"+(e<1?"n ":" ")+r}});var vr={};pe.transitional=function(e,t,i){function n(s,o){return"[Axios v"+Mt+"] Transitional option '"+s+"'"+o+(i?". "+i:"")}return function(s,o,u){if(e===!1)throw new O(n(o," has been removed"+(t?" in "+t:"")),O.ERR_DEPRECATED);return t&&!vr[o]&&(vr[o]=!0,console.warn(n(o," has been deprecated since v"+t+" and will be removed in the near future"))),e?e(s,o,u):!0}};function kt(r,e,t){if(typeof r!="object")throw new O("options must be an object",O.ERR_BAD_OPTION_VALUE);for(var i=Object.keys(r),n=i.length;n-- >0;){var s=i[n],o=e[s];if(o){var u=r[s],f=u===void 0||o(u,s,r);if(f!==!0)throw new O("option "+s+" must be "+f,O.ERR_BAD_OPTION_VALUE);continue}if(t!==!0)throw new O("Unknown option "+s,O.ERR_BAD_OPTION)}}Er.exports={assertOptions:kt,validators:pe}});var qr=l((Nn,Or)=>{"use strict";var wr=d(),Vt=ee(),Rr=Te(),xr=pr(),M=ce(),Jt=ie(),br=yr(),N=br.validators;function _(r){this.defaults=r,this.interceptors={request:new Rr,response:new Rr}}_.prototype.request=function(e,t){typeof e=="string"?(t=t||{},t.url=e):t=e||{},t=M(this.defaults,t),t.method?t.method=t.method.toLowerCase():this.defaults.method?t.method=this.defaults.method.toLowerCase():t.method="get";var i=t.transitional;i!==void 0&&br.assertOptions(i,{silentJSONParsing:N.transitional(N.boolean),forcedJSONParsing:N.transitional(N.boolean),clarifyTimeoutError:N.transitional(N.boolean)},!1);var n=[],s=!0;this.interceptors.request.forEach(function(v){typeof v.runWhen=="function"&&v.runWhen(t)===!1||(s=s&&v.synchronous,n.unshift(v.fulfilled,v.rejected))});var o=[];this.interceptors.response.forEach(function(v){o.push(v.fulfilled,v.rejected)});var u;if(!s){var f=[xr,void 0];for(Array.prototype.unshift.apply(f,n),f=f.concat(o),u=Promise.resolve(t);f.length;)u=u.then(f.shift(),f.shift());return u}for(var h=t;n.length;){var a=n.shift(),c=n.shift();try{h=a(h)}catch(y){c(y);break}}try{u=xr(h)}catch(y){return Promise.reject(y)}for(;o.length;)u=u.then(o.shift(),o.shift());return u};_.prototype.getUri=function(e){e=M(this.defaults,e);var t=Jt(e.baseURL,e.url);return Vt(t,e.params,e.paramsSerializer)};wr.forEach(["delete","get","head","options"],function(e){_.prototype[e]=function(t,i){return this.request(M(i||{},{method:e,url:t,data:(i||{}).data}))}});wr.forEach(["post","put","patch"],function(e){function t(i){return function(s,o,u){return this.request(M(u||{},{method:e,headers:i?{"Content-Type":"multipart/form-data"}:{},url:s,data:o}))}}_.prototype[e]=t(),_.prototype[e+"Form"]=t(!0)});Or.exports=_});var Sr=l((_n,Ar)=>{"use strict";var Wt=D();function P(r){if(typeof r!="function")throw new TypeError("executor must be a function.");var e;this.promise=new Promise(function(n){e=n});var t=this;this.promise.then(function(i){if(!!t._listeners){var n,s=t._listeners.length;for(n=0;n{"use strict";gr.exports=function(e){return function(i){return e.apply(null,i)}}});var Nr=l((Dn,Cr)=>{"use strict";var zt=d();Cr.exports=function(e){return zt.isObject(e)&&e.isAxiosError===!0}});var Dr=l((Un,he)=>{"use strict";var _r=d(),Xt=X(),k=qr(),$t=ce(),Yt=H();function Pr(r){var e=new k(r),t=Xt(k.prototype.request,e);return _r.extend(t,k.prototype,e),_r.extend(t,e),t.create=function(n){return Pr($t(r,n))},t}var E=Pr(Yt);E.Axios=k;E.CanceledError=D();E.CancelToken=Sr();E.isCancel=ue();E.VERSION=de().version;E.toFormData=te();E.AxiosError=S();E.Cancel=E.CanceledError;E.all=function(e){return Promise.all(e)};E.spread=Tr();E.isAxiosError=Nr();he.exports=E;he.exports.default=E});var Br=l((Bn,Ur)=>{Ur.exports=Dr()});var jr=Xr(Br());var V,Kt=new Uint8Array(16);function me(){if(!V&&(V=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||typeof msCrypto<"u"&&typeof msCrypto.getRandomValues=="function"&&msCrypto.getRandomValues.bind(msCrypto),!V))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return V(Kt)}var Lr=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function Gt(r){return typeof r=="string"&&Lr.test(r)}var Ir=Gt;var m=[];for(J=0;J<256;++J)m.push((J+256).toString(16).substr(1));var J;function Qt(r){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0,t=(m[r[e+0]]+m[r[e+1]]+m[r[e+2]]+m[r[e+3]]+"-"+m[r[e+4]]+m[r[e+5]]+"-"+m[r[e+6]]+m[r[e+7]]+"-"+m[r[e+8]]+m[r[e+9]]+"-"+m[r[e+10]]+m[r[e+11]]+m[r[e+12]]+m[r[e+13]]+m[r[e+14]]+m[r[e+15]]).toLowerCase();if(!Ir(t))throw TypeError("Stringified UUID is invalid");return t}var Fr=Qt;function Zt(r,e,t){r=r||{};var i=r.random||(r.rng||me)();if(i[6]=i[6]&15|64,i[8]=i[8]&63|128,e){t=t||0;for(var n=0;n<16;++n)e[t+n]=i[n];return e}return Fr(i)}var ve=Zt;function rn(){let r="__telemetry_session";return localStorage.getItem(r)===null&&localStorage.setItem(r,ve()),localStorage.getItem(r)}var Ee=class{constructor(e,t,i){this.url=e;this.commitHash=t;this.branch=i;this.sessionId=rn()}log(e,t){if(!(this.branch=="main"||this.branch=="master")||window.location.hostname=="localhost"&&!this.url.includes("localhost"))return;let n={sessionId:this.sessionId,commitHash:this.commitHash,timestamp:new Date().getTime(),payload:t},s=this.url+"/"+e;console.debug(`Logging to ${s}:`,n),jr.default.post(s,n)}};typeof window<"u"&&(window.telemetry=new Ee("https://rust-book.willcrichton.net/logs","c180abe6f28cab774368ef7c9189ee3f2905670b","main"));})();
diff --git a/print.html b/print.html
index 738aa0bccd..38b58e39ec 100644
--- a/print.html
+++ b/print.html
@@ -174,6 +174,11 @@ 2. Highlighting
3. …and more!
The book’s content may change as you go through the experiment. We will update this page as we add new features. Here’s the changelog:
+- September 26, 2024
+
+- Chris Krycho’s chapter on async Rust has been added, along with new quiz questions.
+
+
- February 16, 2023
- A new chapter on ownership has replaced the previous Chapter 4.
@@ -200,7 +205,19 @@ 3. …and more!
Interested in participating in other experiments about making Rust easier to learn? Please sign up here: https://forms.gle/U3jEUkb2fGXykp1DA
-4. Acknowledgments
+4. Publications
+Thus far, this experiment has led to two open-access publications. Check them out if you’re interested to see the academic research behind this book:
+
+-
+
Profiling Programming Language Learning
+Will Crichton and Shriram Krishnamurthi. OOPSLA 2024. (Distinguished Paper!)
+
+-
+
A Grounded Conceptual Model for Ownership Types in Rust
+Will Crichton, Gavin Gray, and Shriram Krishnamurthi. OOPSLA 2023.
+
+
+5. Acknowledgments
Niko Matsakis and Amazon Web Services provided funding for this experiment. Carol Nichols and the Rust Foundation helped publicize the experiment. TRPL is the product of many people’s hard work before we started this experiment.
The Rust Programming Language
by Steve Klabnik and Carol Nichols, with contributions from the Rust Community
@@ -3534,7 +3551,7 @@
The macro vec!
creates a vector with the elements between the brackets. The vector v
has type Vec<i32>
. The syntax <i32>
means the elements of the vector have type i32
.
One important implementation detail is that v
allocates a heap array of a certain capacity. We can peek into Vec
’s internals and see this detail for ourselves:
-
+
Note: click the binocular icon in the top right of the diagram to toggle this detailed view in any runtime diagram.
@@ -3595,7 +3612,7 @@ The Borrow Checker Finds Permission Violations
Recall the Pointer Safety Principle: data should not be aliased and mutated. The goal of these permissions is to ensure that data cannot be mutated if it is aliased. Creating a reference to data (“borrowing” it) causes that data to be temporarily read-only until the reference is no longer in use.
Rust uses these permissions in its borrow checker. The borrow checker looks for potentially unsafe operations involving references. Let’s return to the unsafe program we saw earlier, where push
invalidates a reference. This time we’ll add another aspect to the permissions diagram:
-
+
Any time a place is used, Rust expects that place to have certain permissions depending on the operation. For example, the borrow &v[2]
requires that v
is readable. Therefore the R permission is shown between the operation &
and the place v
. The letter is filled-in because v
has the read permission at that line.
By contrast, the mutating operation v.push(4)
requires that v
is readable and writable. Both R and W are shown. However, v
does not have write permissions (it is borrowed by num
). So the letter W is hollow, indicating that the write permission is expected but v
does not have it.
If you try to compile this program, then the Rust compiler will return the following error:
@@ -3623,7 +3640,7 @@ The first observation is what makes mutable references safe. Mutable references allow mutation but prevent aliasing. The borrowed place v
becomes temporarily unusable, so effectively not an alias.
The second observation is what makes mutable references useful. v[2]
can be mutated through *num
. For example, *num += 1
mutates v[2]
. Note that *num
has the W permission, but num
does not. num
refers to the mutable reference itself, e.g. num
cannot be reassigned to a different mutable reference.
Mutable references can also be temporarily “downgraded” to read-only references. For example:
-
+
Note: when permission changes are not relevant to an example, we will hide them. You can view hidden steps by clicking “»”, and you can view hidden permissions within a step by clicking “● ● ●”.
@@ -3634,13 +3651,13 @@
The W permission on x
is returned to x
after the lifetime of y
has ended, like we have seen before.
In the previous examples, a lifetime has been a contiguous region of code. However, once we introduce control flow, this is not necessarily the case. For example, here is a function that capitalizes the first character in a vector of ASCII characters:
-
+
The variable c
has a different lifetime in each branch of the if-statement. In the then-block, c
is used in the expression c.to_ascii_uppercase()
. Therefore *v
does not regain the W permission until after that line.
However, in the else-block, c
is not used. *v
immediately regains the W permission on entry to the else-block.
Data Must Outlive All Of Its References
As a part of the Pointer Safety Principle, the borrow checker enforces that data must outlive any references to it. Rust enforces this property in two ways. The first way deals with references that are created and dropped within the scope of a single function. For example, say we tried to drop a string while holding a reference to it:
-
+
To catch these kinds of errors, Rust uses the permissions we’ve already discussed. The borrow &s
removes the O permission from s
. However, drop
expects the O permission, leading to a permission mismatch.
The key idea is that in this example, Rust knows how long s_ref
lives. But Rust needs a different enforcement mechanism when it doesn’t know how long a reference lives. Specifically, when references are either input to a function, or output from a function. For example, here is a safe function that returns a reference to the first element in a vector:
@@ -3667,7 +3684,7 @@ “Validating References with Lifetimes”. For now, it’s enough to know that: (1) input/output references are treated differently than references within a function body, and (2) Rust uses a different mechanism, the F permission, to check the safety of those references.
To see the F permission in another context, say you tried to return a reference to a variable on the stack like this:
-
+
This program is unsafe because the reference &s
will be invalidated when return_a_string
returns. And Rust will reject this program with a similar missing lifetime specifier
error. Now you can understand that error means that s_ref
is missing the appropriate flow permissions.
Summary
@@ -3729,7 +3746,7 @@ Fixing an Unsafe Program: Not Enough Permissions
Another common issue is trying to mutate read-only data, or trying to drop data behind a reference. For example, let’s say we tried to write a function stringify_name_with_title
. This function is supposed to create a person’s full name from a vector of name parts, including an extra title.
-
+
This program is rejected by the borrow checker because name
is an immutable reference, but name.push(..)
requires the W permission. This program is unsafe because push
could invalidate other references to name
outside of stringify_name_with_title
, like this:
In this example, a reference first
to name[0]
is created before calling stringify_name_with_title
. The function name.push(..)
reallocates the contents of name
, which invalidates first
, causing the println
to read deallocated memory.
@@ -3765,7 +3782,7 @@
Fixing an Unsafe Program: Aliasing and Mutating a Data Structure
Another unsafe operation is using a reference to heap data that gets deallocated by another alias. For example, here’s a function that gets a reference to the largest string in a vector, and then uses it while mutating the vector:
-
+
Note: this example uses iterators and closures to succinctly find a reference to the largest string. We will discuss those features in later chapters, and for now we will provide an intuitive sense of how the features work here.
@@ -3810,7 +3827,7 @@ These solutions all share in common the key idea: shortening the lifetime of borrows on dst
to not overlap with a mutation to dst
.
Fixing an Unsafe Program: Copying vs. Moving Out of a Collection
A common confusion for Rust learners happens when copying data out of a collection, like a vector. For example, here’s a safe program that copies a number out of a vector:
-
+
The dereference operation *n_ref
expects just the R permission, which the path *n_ref
has. But what happens if we change the type of elements in the vector from i32
to String
? Then it turns out we no longer have the necessary permissions:
The first program will compile, but the second program will not compile. Rust gives the following error message:
@@ -3868,10 +3885,10 @@ Fixing a Safe Program: Mutating Different Tuple Fields
The above examples are cases where a program is unsafe. Rust may also reject safe programs. One common issue is that Rust tries to track permissions at a fine-grained level. However, Rust may conflate two different places as the same place.
Let’s first look at an example of fine-grained permission tracking that passes the borrow checker. This program shows how you can borrow one field of a tuple, and write to a different field of the same tuple:
-
+
The statement let first = &name.0
borrows name.0
. This borrow removes WO permissions from name.0
. It also removes WO permissions from name
. (For example, one could not pass name
to a function that takes as input a value of type (String, String)
.) But name.1
still retains the W permission, so doing name.1.push_str(...)
is a valid operation.
However, Rust can lose track of exactly which places are borrowed. For example, let’s say we refactor the expression &name.0
into a function get_first
. Notice how after calling get_first(&name)
, Rust now removes the W permission on name.1
:
-
+
Now we can’t do name.1.push_str(..)
! Rust will return this error:
error[E0502]: cannot borrow `name.1` as mutable because it is also borrowed as immutable
--> test.rs:11:5
@@ -3893,7 +3910,7 @@ let idx = a_complex_function();
let x = &mut a[idx];
What is the value of idx
? Rust isn’t going to guess, so it assumes idx
could be anything. For example, let’s say we try to read from one array index while writing to a different one:
-
+
However, Rust will reject this program because a
gave its read permission to x
. The compiler’s error message says the same thing:
error[E0502]: cannot borrow `a[_]` as immutable because it is also borrowed as mutable
--> test.rs:4:9
@@ -4025,7 +4042,7 @@ Summary
will still be valid in the future. Consider the program in Listing 4-8 that
uses the first_word
function from Listing 4-7.
Filename: src/main.rs
-
+
This program compiles without any errors, as s
retains write permissions
@@ -4135,7 +4152,7 @@
Filename: src/main.rs
-
+
You can see that calling first_word
now removes the write permission from s
,
which prevents us from calling s.clear()
. Here’s the compiler error:
$ cargo run
@@ -4387,9 +4404,9 @@ Own
If you want to review slices, re-read Chapter 4.4.
Ownership at Compile-time
Rust tracks R (read), W (write), and O (own) permissions on each variable. Rust requires that a variable has appropriate permissions to perform a given operation. As a basic example, if a variable is not declared as let mut
, then it is missing the W permission and cannot be mutated:
-
+
A variable’s permissions can be changed if it is moved or borrowed. A move of a variable with a non-copyable type (like Box<T>
or String
) requires the RO permissions, and the move eliminates all permissions on the variable. That rule prevents the use of moved variables:
-
+
If you want to review how moves work, re-read Chapter 4.1.
Borrowing a variable (creating a reference to it) temporarily removes some of the variable’s permissions. An immutable borrow creates an immutable reference, and also disables the borrowed data from being mutated or moved. For example, printing an immutable reference is ok:
@@ -4398,11 +4415,11 @@
And moving data out of the reference is not ok:
-
+
A mutable borrow creates a mutable reference, which disables the borrowed data from being read, written, or moved. For example, mutating a mutable reference is ok:
-
+
But accessing the mutably borrowed data is not ok:
-
+
If you want to review permissions and references, re-read Chapter 4.2.
Connecting Ownership between Compile-time and Runtime
Rust’s permissions are designed to prevent undefined behavior. For example, one kind of undefined behavior is a use-after-free where freed memory is read or written. Immutable borrows remove the W permission to avoid use-after-free, like in this case:
@@ -4413,7 +4430,7 @@ The Rest of Ownership
As we introduce additional features like structs, enums, and traits, those features will have specific interactions with ownership. This chapter provides the essential foundation for understanding those interactions — the concepts of memory, pointers, undefined behavior, and permissions will help us talk about the more advanced parts of Rust in future chapters.
And don’t forget to take the quizzes if you want to check your understanding!
-
+
1
In fact, the original invention of ownership types wasn’t about memory safety at all. It was about preventing leaks of mutable references to data structure internals in Java-like languages. If you’re curious to learn more about the history of ownership types, check out the paper “Ownership Types for Flexible Alias Protection” (Clarke et al. 1998).
@@ -4707,9 +4724,9 @@ Borrowing Fields of a Struct
Similar to our discussion in “Different Tuple Fields”, Rust’s borrow checker will track ownership permissions
at both the struct-level and field-level. For example, if we borrow a field x
of a Point
structure, then both p
and p.x
temporarily lose their permissions (but not p.y
):
-
+
As a result, if we try and use p
while p.x
is mutably borrowed like this:
-
+
Then the compiler will reject our program with the following error:
error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
--> test.rs:10:17
@@ -5405,10 +5422,10 @@
+
Moves with self
Calling a method that expects self
will move the input struct (unless the struct implements Copy
). For example, we cannot use a Rectangle
after passing it to max
:
-
+
Once we call rect.max(..)
, we move rect
and so lose all permissions on it. Trying to compile this program would give us the following error:
error[E0382]: borrow of moved value: `rect`
--> test.rs:33:16
@@ -5422,7 +5439,7 @@ Moves with
A similar situation arises if we try to call a self
method on a reference. For instance, say we tried to make a method set_to_max
that assigns self
to the output of self.max(..)
:
-
+
Then we can see that self
is missing O permissions in the operation self.max(..)
. Rust therefore rejects this program with the following error:
error[E0507]: cannot move out of `*self` which is behind a mutable reference
--> test.rs:23:17
@@ -6171,12 +6188,12 @@ How Matches Interact with Ownership
If an enum contains non-copyable data like a String, then you should be careful with whether a match will move or borrow that data. For example, this program using an Option<String>
will compile:
-
+
But if we replace the placeholder in Some(_)
with a variable name, like Some(s)
, then the program will NOT compile:
-
+
opt
is a plain enum — its type is Option<String>
and not a reference like &Option<String>
. Therefore a match on opt
will move non-ignored fields like s
. Notice how opt
loses read and own permission sooner in the second program compared to the first. After the match expression, the data within opt
has been moved, so it is illegal to read opt
in the println
.
If we want to peek into opt
without moving its contents, the idiomatic solution is to match on a reference:
-
+
Rust will “push down” the reference from the outer enum, &Option<String>
, to the inner field, &String
. Therefore s
has type &String
, and opt
can be used after the match. To better understand this “pushing down” mechanism, see the section about binding modes in the Rust Reference.
@@ -15664,7 +15681,7 @@ }
These changes say: s_ref
is a string reference that lives for 'a
. Adding + 'a
to the return type’s trait bounds indicates that the closure must live no longer than 'a
. Therefore Rust deduces this function is now safe. If we try to use it unsafely like before:
-
+
Rust recognizes that as long as make_a_cloner
is in use, s_own
cannot be dropped. This is reflected in the permissions: s_own
loses the O permission after calling make_a_cloner
. Consequently, Rust rejects this program with the following error:
error[E0505]: cannot move out of `s_own` because it is borrowed
--> test.rs:9:6
diff --git a/searchindex.js b/searchindex.js
index ccf448735e..7d605d3488 100644
--- a/searchindex.js
+++ b/searchindex.js
@@ -1 +1 @@
-Object.assign(window.search, {"doc_urls":["experiment-intro.html#experiment-introduction","experiment-intro.html#1-quizzes","experiment-intro.html#2-highlighting","experiment-intro.html#3-and-more","experiment-intro.html#4-acknowledgments","title-page.html#the-rust-programming-language","foreword.html#foreword","ch00-00-introduction.html#introduction","ch00-00-introduction.html#who-rust-is-for","ch00-00-introduction.html#teams-of-developers","ch00-00-introduction.html#students","ch00-00-introduction.html#companies","ch00-00-introduction.html#open-source-developers","ch00-00-introduction.html#people-who-value-speed-and-stability","ch00-00-introduction.html#who-this-book-is-for","ch00-00-introduction.html#how-to-use-this-book","ch00-00-introduction.html#source-code","ch01-00-getting-started.html#getting-started","ch01-01-installation.html#installation","ch01-01-installation.html#command-line-notation","ch01-01-installation.html#installing-rustup-on-linux-or-macos","ch01-01-installation.html#installing-rustup-on-windows","ch01-01-installation.html#troubleshooting","ch01-01-installation.html#updating-and-uninstalling","ch01-01-installation.html#local-documentation","ch01-02-hello-world.html#hello-world","ch01-02-hello-world.html#creating-a-project-directory","ch01-02-hello-world.html#writing-and-running-a-rust-program","ch01-02-hello-world.html#anatomy-of-a-rust-program","ch01-02-hello-world.html#compiling-and-running-are-separate-steps","ch01-03-hello-cargo.html#hello-cargo","ch01-03-hello-cargo.html#creating-a-project-with-cargo","ch01-03-hello-cargo.html#building-and-running-a-cargo-project","ch01-03-hello-cargo.html#building-for-release","ch01-03-hello-cargo.html#cargo-as-convention","ch01-03-hello-cargo.html#summary","ch02-00-guessing-game-tutorial.html#programming-a-guessing-game","ch02-00-guessing-game-tutorial.html#setting-up-a-new-project","ch02-00-guessing-game-tutorial.html#processing-a-guess","ch02-00-guessing-game-tutorial.html#storing-values-with-variables","ch02-00-guessing-game-tutorial.html#receiving-user-input","ch02-00-guessing-game-tutorial.html#handling-potential-failure-with-result","ch02-00-guessing-game-tutorial.html#printing-values-with-println-placeholders","ch02-00-guessing-game-tutorial.html#testing-the-first-part","ch02-00-guessing-game-tutorial.html#generating-a-secret-number","ch02-00-guessing-game-tutorial.html#using-a-crate-to-get-more-functionality","ch02-00-guessing-game-tutorial.html#generating-a-random-number","ch02-00-guessing-game-tutorial.html#comparing-the-guess-to-the-secret-number","ch02-00-guessing-game-tutorial.html#allowing-multiple-guesses-with-looping","ch02-00-guessing-game-tutorial.html#quitting-after-a-correct-guess","ch02-00-guessing-game-tutorial.html#handling-invalid-input","ch02-00-guessing-game-tutorial.html#summary","ch03-00-common-programming-concepts.html#common-programming-concepts","ch03-01-variables-and-mutability.html#variables-and-mutability","ch03-01-variables-and-mutability.html#constants","ch03-01-variables-and-mutability.html#shadowing","ch03-02-data-types.html#data-types","ch03-02-data-types.html#scalar-types","ch03-02-data-types.html#compound-types","ch03-03-how-functions-work.html#functions","ch03-03-how-functions-work.html#parameters","ch03-03-how-functions-work.html#statements-and-expressions","ch03-03-how-functions-work.html#functions-with-return-values","ch03-04-comments.html#comments","ch03-05-control-flow.html#control-flow","ch03-05-control-flow.html#if-expressions","ch03-05-control-flow.html#repetition-with-loops","ch03-05-control-flow.html#summary","ch04-00-understanding-ownership.html#understanding-ownership","ch04-01-what-is-ownership.html#what-is-ownership","ch04-01-what-is-ownership.html#safety-is-the-absence-of-undefined-behavior","ch04-01-what-is-ownership.html#ownership-as-a-discipline-for-memory-safety","ch04-01-what-is-ownership.html#variables-live-in-the-stack","ch04-01-what-is-ownership.html#boxes-live-in-the-heap","ch04-01-what-is-ownership.html#rust-does-not-permit-manual-memory-management","ch04-01-what-is-ownership.html#a-boxs-owner-manages-deallocation","ch04-01-what-is-ownership.html#collections-use-boxes","ch04-01-what-is-ownership.html#variables-cannot-be-used-after-being-moved","ch04-01-what-is-ownership.html#cloning-avoids-moves","ch04-01-what-is-ownership.html#summary","ch04-02-references-and-borrowing.html#references-and-borrowing","ch04-02-references-and-borrowing.html#references-are-non-owning-pointers","ch04-02-references-and-borrowing.html#dereferencing-a-pointer-accesses-its-data","ch04-02-references-and-borrowing.html#rust-avoids-simultaneous-aliasing-and-mutation","ch04-02-references-and-borrowing.html#references-change-permissions-on-places","ch04-02-references-and-borrowing.html#the-borrow-checker-finds-permission-violations","ch04-02-references-and-borrowing.html#mutable-references-provide-unique-and-non-owning-access-to-data","ch04-02-references-and-borrowing.html#permissions-are-returned-at-the-end-of-a-references-lifetime","ch04-02-references-and-borrowing.html#data-must-outlive-all-of-its-references","ch04-02-references-and-borrowing.html#summary","ch04-03-fixing-ownership-errors.html#fixing-ownership-errors","ch04-03-fixing-ownership-errors.html#fixing-an-unsafe-program-returning-a-reference-to-the-stack","ch04-03-fixing-ownership-errors.html#fixing-an-unsafe-program-not-enough-permissions","ch04-03-fixing-ownership-errors.html#fixing-an-unsafe-program-aliasing-and-mutating-a-data-structure","ch04-03-fixing-ownership-errors.html#fixing-an-unsafe-program-copying-vs-moving-out-of-a-collection","ch04-03-fixing-ownership-errors.html#fixing-a-safe-program-mutating-different-tuple-fields","ch04-03-fixing-ownership-errors.html#fixing-a-safe-program-mutating-different-array-elements","ch04-03-fixing-ownership-errors.html#summary","ch04-04-slices.html#the-slice-type","ch04-04-slices.html#string-slices","ch04-04-slices.html#other-slices","ch04-04-slices.html#summary","ch04-05-ownership-recap.html#ownership-recap","ch04-05-ownership-recap.html#ownership-versus-garbage-collection","ch04-05-ownership-recap.html#the-concepts-of-ownership","ch04-05-ownership-recap.html#the-rest-of-ownership","ch05-00-structs.html#using-structs-to-structure-related-data","ch05-01-defining-structs.html#defining-and-instantiating-structs","ch05-01-defining-structs.html#using-the-field-init-shorthand","ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax","ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types","ch05-01-defining-structs.html#unit-like-structs-without-any-fields","ch05-01-defining-structs.html#ownership-of-struct-data","ch05-01-defining-structs.html#borrowing-fields-of-a-struct","ch05-02-example-structs.html#an-example-program-using-structs","ch05-02-example-structs.html#refactoring-with-tuples","ch05-02-example-structs.html#refactoring-with-structs-adding-more-meaning","ch05-02-example-structs.html#adding-useful-functionality-with-derived-traits","ch05-03-method-syntax.html#method-syntax","ch05-03-method-syntax.html#defining-methods","ch05-03-method-syntax.html#methods-with-more-parameters","ch05-03-method-syntax.html#associated-functions","ch05-03-method-syntax.html#multiple-impl-blocks","ch05-03-method-syntax.html#method-calls-are-syntactic-sugar-for-function-calls","ch05-03-method-syntax.html#methods-and-ownership","ch05-03-method-syntax.html#summary","ch06-00-enums.html#enums-and-pattern-matching","ch06-01-defining-an-enum.html#defining-an-enum","ch06-01-defining-an-enum.html#enum-values","ch06-01-defining-an-enum.html#the-option-enum-and-its-advantages-over-null-values","ch06-02-match.html#the-match-control-flow-construct","ch06-02-match.html#patterns-that-bind-to-values","ch06-02-match.html#matching-with-option","ch06-02-match.html#matches-are-exhaustive","ch06-02-match.html#catch-all-patterns-and-the-_-placeholder","ch06-02-match.html#how-matches-interact-with-ownership","ch06-03-if-let.html#concise-control-flow-with-if-let","ch06-03-if-let.html#summary","ch06-04-inventory.html#ownership-inventory-1","ch06-04-inventory.html#a-new-technology-the-in-browser-ide","ch06-04-inventory.html#the-quiz","ch07-00-managing-growing-projects-with-packages-crates-and-modules.html#managing-growing-projects-with-packages-crates-and-modules","ch07-01-packages-and-crates.html#packages-and-crates","ch07-02-defining-modules-to-control-scope-and-privacy.html#defining-modules-to-control-scope-and-privacy","ch07-02-defining-modules-to-control-scope-and-privacy.html#modules-cheat-sheet","ch07-02-defining-modules-to-control-scope-and-privacy.html#grouping-related-code-in-modules","ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#paths-for-referring-to-an-item-in-the-module-tree","ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#exposing-paths-with-the-pub-keyword","ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#starting-relative-paths-with-super","ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#making-structs-and-enums-public","ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#bringing-paths-into-scope-with-the-use-keyword","ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#creating-idiomatic-use-paths","ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#providing-new-names-with-the-as-keyword","ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#re-exporting-names-with-pub-use","ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#using-external-packages","ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#using-nested-paths-to-clean-up-large-use-lists","ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#the-glob-operator","ch07-05-separating-modules-into-different-files.html#separating-modules-into-different-files","ch07-05-separating-modules-into-different-files.html#alternate-file-paths","ch07-05-separating-modules-into-different-files.html#summary","ch08-00-common-collections.html#common-collections","ch08-01-vectors.html#storing-lists-of-values-with-vectors","ch08-01-vectors.html#creating-a-new-vector","ch08-01-vectors.html#updating-a-vector","ch08-01-vectors.html#reading-elements-of-vectors","ch08-01-vectors.html#iterating-over-the-values-in-a-vector","ch08-01-vectors.html#safely-using-iterators","ch08-01-vectors.html#using-an-enum-to-store-multiple-types","ch08-01-vectors.html#dropping-a-vector-drops-its-elements","ch08-02-strings.html#storing-utf-8-encoded-text-with-strings","ch08-02-strings.html#what-is-a-string","ch08-02-strings.html#creating-a-new-string","ch08-02-strings.html#updating-a-string","ch08-02-strings.html#indexing-into-strings","ch08-02-strings.html#slicing-strings","ch08-02-strings.html#methods-for-iterating-over-strings","ch08-02-strings.html#strings-are-not-so-simple","ch08-03-hash-maps.html#storing-keys-with-associated-values-in-hash-maps","ch08-03-hash-maps.html#creating-a-new-hash-map","ch08-03-hash-maps.html#accessing-values-in-a-hash-map","ch08-03-hash-maps.html#hash-maps-and-ownership","ch08-03-hash-maps.html#updating-a-hash-map","ch08-03-hash-maps.html#hashing-functions","ch08-03-hash-maps.html#summary","ch08-04-inventory.html#ownership-inventory-2","ch09-00-error-handling.html#error-handling","ch09-01-unrecoverable-errors-with-panic.html#unrecoverable-errors-with-panic","ch09-01-unrecoverable-errors-with-panic.html#unwinding-the-stack-or-aborting-in-response-to-a-panic","ch09-02-recoverable-errors-with-result.html#recoverable-errors-with-result","ch09-02-recoverable-errors-with-result.html#matching-on-different-errors","ch09-02-recoverable-errors-with-result.html#propagating-errors","ch09-03-to-panic-or-not-to-panic.html#to-panic-or-not-to-panic","ch09-03-to-panic-or-not-to-panic.html#examples-prototype-code-and-tests","ch09-03-to-panic-or-not-to-panic.html#cases-in-which-you-have-more-information-than-the-compiler","ch09-03-to-panic-or-not-to-panic.html#guidelines-for-error-handling","ch09-03-to-panic-or-not-to-panic.html#creating-custom-types-for-validation","ch09-03-to-panic-or-not-to-panic.html#summary","ch10-00-generics.html#generic-types-traits-and-lifetimes","ch10-00-generics.html#removing-duplication-by-extracting-a-function","ch10-01-syntax.html#generic-data-types","ch10-01-syntax.html#in-function-definitions","ch10-01-syntax.html#in-struct-definitions","ch10-01-syntax.html#in-enum-definitions","ch10-01-syntax.html#in-method-definitions","ch10-01-syntax.html#performance-of-code-using-generics","ch10-02-traits.html#traits-defining-shared-behavior","ch10-02-traits.html#defining-a-trait","ch10-02-traits.html#implementing-a-trait-on-a-type","ch10-02-traits.html#default-implementations","ch10-02-traits.html#traits-as-parameters","ch10-02-traits.html#returning-types-that-implement-traits","ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods","ch10-03-lifetime-syntax.html#validating-references-with-lifetimes","ch10-03-lifetime-syntax.html#preventing-dangling-references-with-lifetimes","ch10-03-lifetime-syntax.html#the-borrow-checker-ensures-data-outlives-its-references","ch10-03-lifetime-syntax.html#generic-lifetimes-in-functions","ch10-03-lifetime-syntax.html#lifetime-annotation-syntax","ch10-03-lifetime-syntax.html#lifetime-annotations-in-function-signatures","ch10-03-lifetime-syntax.html#thinking-in-terms-of-lifetimes","ch10-03-lifetime-syntax.html#lifetime-annotations-in-struct-definitions","ch10-03-lifetime-syntax.html#lifetime-elision","ch10-03-lifetime-syntax.html#lifetime-annotations-in-method-definitions","ch10-03-lifetime-syntax.html#the-static-lifetime","ch10-03-lifetime-syntax.html#generic-type-parameters-trait-bounds-and-lifetimes-together","ch10-03-lifetime-syntax.html#summary","ch10-04-inventory.html#ownership-inventory-3","ch11-00-testing.html#writing-automated-tests","ch11-01-writing-tests.html#how-to-write-tests","ch11-01-writing-tests.html#the-anatomy-of-a-test-function","ch11-01-writing-tests.html#checking-results-with-the-assert-macro","ch11-01-writing-tests.html#testing-equality-with-the-assert_eq-and-assert_ne-macros","ch11-01-writing-tests.html#adding-custom-failure-messages","ch11-01-writing-tests.html#checking-for-panics-with-should_panic","ch11-01-writing-tests.html#using-result-in-tests","ch11-02-running-tests.html#controlling-how-tests-are-run","ch11-02-running-tests.html#running-tests-in-parallel-or-consecutively","ch11-02-running-tests.html#showing-function-output","ch11-02-running-tests.html#running-a-subset-of-tests-by-name","ch11-02-running-tests.html#ignoring-some-tests-unless-specifically-requested","ch11-03-test-organization.html#test-organization","ch11-03-test-organization.html#unit-tests","ch11-03-test-organization.html#integration-tests","ch11-03-test-organization.html#summary","ch12-00-an-io-project.html#an-io-project-building-a-command-line-program","ch12-01-accepting-command-line-arguments.html#accepting-command-line-arguments","ch12-01-accepting-command-line-arguments.html#reading-the-argument-values","ch12-01-accepting-command-line-arguments.html#the-args-function-and-invalid-unicode","ch12-01-accepting-command-line-arguments.html#saving-the-argument-values-in-variables","ch12-02-reading-a-file.html#reading-a-file","ch12-03-improving-error-handling-and-modularity.html#refactoring-to-improve-modularity-and-error-handling","ch12-03-improving-error-handling-and-modularity.html#separation-of-concerns-for-binary-projects","ch12-03-improving-error-handling-and-modularity.html#the-trade-offs-of-using-clone","ch12-03-improving-error-handling-and-modularity.html#fixing-the-error-handling","ch12-03-improving-error-handling-and-modularity.html#extracting-logic-from-main","ch12-03-improving-error-handling-and-modularity.html#splitting-code-into-a-library-crate","ch12-04-testing-the-librarys-functionality.html#developing-the-librarys-functionality-with-test-driven-development","ch12-04-testing-the-librarys-functionality.html#writing-a-failing-test","ch12-04-testing-the-librarys-functionality.html#writing-code-to-pass-the-test","ch12-05-working-with-environment-variables.html#working-with-environment-variables","ch12-05-working-with-environment-variables.html#writing-a-failing-test-for-the-case-insensitive-search-function","ch12-05-working-with-environment-variables.html#implementing-the-search_case_insensitive-function","ch12-06-writing-to-stderr-instead-of-stdout.html#writing-error-messages-to-standard-error-instead-of-standard-output","ch12-06-writing-to-stderr-instead-of-stdout.html#checking-where-errors-are-written","ch12-06-writing-to-stderr-instead-of-stdout.html#printing-errors-to-standard-error","ch12-06-writing-to-stderr-instead-of-stdout.html#summary","ch13-00-functional-features.html#functional-language-features-iterators-and-closures","ch13-01-closures.html#closures-anonymous-functions-that-capture-their-environment","ch13-01-closures.html#capturing-the-environment-with-closures","ch13-01-closures.html#closure-type-inference-and-annotation","ch13-01-closures.html#capturing-references-or-moving-ownership","ch13-01-closures.html#moving-captured-values-out-of-closures-and-the-fn-traits","ch13-01-closures.html#closures-must-name-captured-lifetimes","ch13-02-iterators.html#processing-a-series-of-items-with-iterators","ch13-02-iterators.html#the-iterator-trait-and-the-next-method","ch13-02-iterators.html#methods-that-consume-the-iterator","ch13-02-iterators.html#methods-that-produce-other-iterators","ch13-02-iterators.html#using-closures-that-capture-their-environment","ch13-03-improving-our-io-project.html#improving-our-io-project","ch13-03-improving-our-io-project.html#removing-a-clone-using-an-iterator","ch13-03-improving-our-io-project.html#making-code-clearer-with-iterator-adaptors","ch13-03-improving-our-io-project.html#choosing-between-loops-or-iterators","ch13-04-performance.html#comparing-performance-loops-vs-iterators","ch13-04-performance.html#summary","ch14-00-more-about-cargo.html#more-about-cargo-and-cratesio","ch14-01-release-profiles.html#customizing-builds-with-release-profiles","ch14-02-publishing-to-crates-io.html#publishing-a-crate-to-cratesio","ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments","ch14-02-publishing-to-crates-io.html#exporting-a-convenient-public-api-with-pub-use","ch14-02-publishing-to-crates-io.html#setting-up-a-cratesio-account","ch14-02-publishing-to-crates-io.html#adding-metadata-to-a-new-crate","ch14-02-publishing-to-crates-io.html#publishing-to-cratesio","ch14-02-publishing-to-crates-io.html#publishing-a-new-version-of-an-existing-crate","ch14-02-publishing-to-crates-io.html#deprecating-versions-from-cratesio-with-cargo-yank","ch14-03-cargo-workspaces.html#cargo-workspaces","ch14-03-cargo-workspaces.html#creating-a-workspace","ch14-03-cargo-workspaces.html#creating-the-second-package-in-the-workspace","ch14-04-installing-binaries.html#installing-binaries-with-cargo-install","ch14-05-extending-cargo.html#extending-cargo-with-custom-commands","ch14-05-extending-cargo.html#summary","ch15-00-smart-pointers.html#smart-pointers","ch15-01-box.html#using-box-to-point-to-data-on-the-heap","ch15-01-box.html#using-a-box-to-store-data-on-the-heap","ch15-01-box.html#enabling-recursive-types-with-boxes","ch15-02-deref.html#treating-smart-pointers-like-regular-references-with-the-deref-trait","ch15-02-deref.html#following-the-pointer-to-the-value","ch15-02-deref.html#using-box-like-a-reference","ch15-02-deref.html#defining-our-own-smart-pointer","ch15-02-deref.html#treating-a-type-like-a-reference-by-implementing-the-deref-trait","ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods","ch15-02-deref.html#how-deref-coercion-interacts-with-mutability","ch15-03-drop.html#running-code-on-cleanup-with-the-drop-trait","ch15-03-drop.html#dropping-a-value-early-with-stdmemdrop","ch15-04-rc.html#rc-the-reference-counted-smart-pointer","ch15-04-rc.html#using-rc-to-share-data","ch15-04-rc.html#cloning-an-rc-increases-the-reference-count","ch15-05-interior-mutability.html#refcell-and-the-interior-mutability-pattern","ch15-05-interior-mutability.html#enforcing-borrowing-rules-at-runtime-with-refcell","ch15-05-interior-mutability.html#interior-mutability-a-mutable-borrow-to-an-immutable-value","ch15-05-interior-mutability.html#having-multiple-owners-of-mutable-data-by-combining-rc-and-refcell","ch15-06-reference-cycles.html#reference-cycles-can-leak-memory","ch15-06-reference-cycles.html#creating-a-reference-cycle","ch15-06-reference-cycles.html#preventing-reference-cycles-turning-an-rc-into-a-weak","ch15-06-reference-cycles.html#summary","ch16-00-concurrency.html#fearless-concurrency","ch16-01-threads.html#using-threads-to-run-code-simultaneously","ch16-01-threads.html#creating-a-new-thread-with-spawn","ch16-01-threads.html#waiting-for-all-threads-to-finish-using-join-handles","ch16-01-threads.html#using-move-closures-with-threads","ch16-02-message-passing.html#using-message-passing-to-transfer-data-between-threads","ch16-02-message-passing.html#channels-and-ownership-transference","ch16-02-message-passing.html#sending-multiple-values-and-seeing-the-receiver-waiting","ch16-02-message-passing.html#creating-multiple-producers-by-cloning-the-transmitter","ch16-03-shared-state.html#shared-state-concurrency","ch16-03-shared-state.html#using-mutexes-to-allow-access-to-data-from-one-thread-at-a-time","ch16-03-shared-state.html#similarities-between-refcellrc-and-mutexarc","ch16-04-extensible-concurrency-sync-and-send.html#extensible-concurrency-with-the-sync-and-send-traits","ch16-04-extensible-concurrency-sync-and-send.html#allowing-transference-of-ownership-between-threads-with-send","ch16-04-extensible-concurrency-sync-and-send.html#allowing-access-from-multiple-threads-with-sync","ch16-04-extensible-concurrency-sync-and-send.html#implementing-send-and-sync-manually-is-unsafe","ch16-04-extensible-concurrency-sync-and-send.html#summary","ch17-00-async-await.html#async-and-await","ch17-00-async-await.html#parallelism-and-concurrency","ch17-01-futures-and-syntax.html#futures-and-the-async-syntax","ch17-01-futures-and-syntax.html#our-first-async-program","ch17-02-concurrency-with-async.html#concurrency-with-async","ch17-02-concurrency-with-async.html#counting","ch17-02-concurrency-with-async.html#message-passing","ch17-03-more-futures.html#working-with-any-number-of-futures","ch17-03-more-futures.html#racing-futures","ch17-03-more-futures.html#yielding","ch17-03-more-futures.html#building-our-own-async-abstractions","ch17-04-streams.html#streams","ch17-04-streams.html#composing-streams","ch17-04-streams.html#merging-streams","ch17-05-traits-for-async.html#digging-into-the-traits-for-async","ch17-05-traits-for-async.html#future","ch17-05-traits-for-async.html#pinning-and-the-pin-and-unpin-traits","ch17-05-traits-for-async.html#the-stream-trait","ch17-06-futures-tasks-threads.html#futures-tasks-and-threads","ch17-06-futures-tasks-threads.html#summary","ch18-00-oop.html#object-oriented-programming-features-of-rust","ch18-01-what-is-oo.html#characteristics-of-object-oriented-languages","ch18-01-what-is-oo.html#objects-contain-data-and-behavior","ch18-01-what-is-oo.html#encapsulation-that-hides-implementation-details","ch18-01-what-is-oo.html#inheritance-as-a-type-system-and-as-code-sharing","ch18-01-what-is-oo.html#polymorphism","ch18-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types","ch18-02-trait-objects.html#defining-a-trait-for-common-behavior","ch18-02-trait-objects.html#implementing-the-trait","ch18-02-trait-objects.html#using-the-trait","ch18-02-trait-objects.html#trait-objects-and-type-inference","ch18-02-trait-objects.html#trait-objects-perform-dynamic-dispatch","ch18-03-oo-design-patterns.html#implementing-an-object-oriented-design-pattern","ch18-03-oo-design-patterns.html#defining-post-and-creating-a-new-instance-in-the-draft-state","ch18-03-oo-design-patterns.html#storing-the-text-of-the-post-content","ch18-03-oo-design-patterns.html#ensuring-the-content-of-a-draft-post-is-empty","ch18-03-oo-design-patterns.html#requesting-a-review-of-the-post-changes-its-state","ch18-03-oo-design-patterns.html#adding-approve-to-change-the-behavior-of-content","ch18-03-oo-design-patterns.html#trade-offs-of-the-state-pattern","ch18-03-oo-design-patterns.html#summary","ch18-04-inventory.html#ownership-inventory-4","ch18-05-design-challenge.html#design-trade-offs","ch18-05-design-challenge.html#references","ch18-05-design-challenge.html#trait-trees","ch18-05-design-challenge.html#dispatch","ch18-05-design-challenge.html#intermediates","ch19-00-patterns.html#patterns-and-matching","ch19-01-all-the-places-for-patterns.html#all-the-places-patterns-can-be-used","ch19-01-all-the-places-for-patterns.html#match-arms","ch19-01-all-the-places-for-patterns.html#conditional-if-let-expressions","ch19-01-all-the-places-for-patterns.html#while-let-conditional-loops","ch19-01-all-the-places-for-patterns.html#for-loops","ch19-01-all-the-places-for-patterns.html#let-statements","ch19-01-all-the-places-for-patterns.html#function-parameters","ch19-02-refutability.html#refutability-whether-a-pattern-might-fail-to-match","ch19-03-pattern-syntax.html#pattern-syntax","ch19-03-pattern-syntax.html#matching-literals","ch19-03-pattern-syntax.html#matching-named-variables","ch19-03-pattern-syntax.html#multiple-patterns","ch19-03-pattern-syntax.html#matching-ranges-of-values-with-","ch19-03-pattern-syntax.html#destructuring-to-break-apart-values","ch19-03-pattern-syntax.html#ignoring-values-in-a-pattern","ch19-03-pattern-syntax.html#extra-conditionals-with-match-guards","ch19-03-pattern-syntax.html#-bindings","ch19-03-pattern-syntax.html#summary","ch20-00-advanced-features.html#advanced-features","ch20-01-unsafe-rust.html#unsafe-rust","ch20-01-unsafe-rust.html#unsafe-superpowers","ch20-01-unsafe-rust.html#dereferencing-a-raw-pointer","ch20-01-unsafe-rust.html#calling-an-unsafe-function-or-method","ch20-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable","ch20-01-unsafe-rust.html#implementing-an-unsafe-trait","ch20-01-unsafe-rust.html#accessing-fields-of-a-union","ch20-01-unsafe-rust.html#when-to-use-unsafe-code","ch20-03-advanced-traits.html#advanced-traits","ch20-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types","ch20-03-advanced-traits.html#default-generic-type-parameters-and-operator-overloading","ch20-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name","ch20-03-advanced-traits.html#using-supertraits-to-require-one-traits-functionality-within-another-trait","ch20-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types","ch20-04-advanced-types.html#advanced-types","ch20-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction","ch20-04-advanced-types.html#creating-type-synonyms-with-type-aliases","ch20-04-advanced-types.html#the-never-type-that-never-returns","ch20-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait","ch20-05-advanced-functions-and-closures.html#advanced-functions-and-closures","ch20-05-advanced-functions-and-closures.html#function-pointers","ch20-05-advanced-functions-and-closures.html#returning-closures","ch20-06-macros.html#macros","ch20-06-macros.html#the-difference-between-macros-and-functions","ch20-06-macros.html#declarative-macros-with-macro_rules-for-general-metaprogramming","ch20-06-macros.html#procedural-macros-for-generating-code-from-attributes","ch20-06-macros.html#how-to-write-a-custom-derive-macro","ch20-06-macros.html#attribute-like-macros","ch20-06-macros.html#function-like-macros","ch20-06-macros.html#summary","ch21-00-final-project-a-web-server.html#final-project-building-a-multithreaded-web-server","ch21-01-single-threaded.html#building-a-single-threaded-web-server","ch21-01-single-threaded.html#listening-to-the-tcp-connection","ch21-01-single-threaded.html#reading-the-request","ch21-01-single-threaded.html#a-closer-look-at-an-http-request","ch21-01-single-threaded.html#writing-a-response","ch21-01-single-threaded.html#returning-real-html","ch21-01-single-threaded.html#validating-the-request-and-selectively-responding","ch21-01-single-threaded.html#a-touch-of-refactoring","ch21-02-multithreaded.html#turning-our-single-threaded-server-into-a-multithreaded-server","ch21-02-multithreaded.html#simulating-a-slow-request-in-the-current-server-implementation","ch21-02-multithreaded.html#improving-throughput-with-a-thread-pool","ch21-03-graceful-shutdown-and-cleanup.html#graceful-shutdown-and-cleanup","ch21-03-graceful-shutdown-and-cleanup.html#implementing-the-drop-trait-on-threadpool","ch21-03-graceful-shutdown-and-cleanup.html#signaling-to-the-threads-to-stop-listening-for-jobs","ch21-03-graceful-shutdown-and-cleanup.html#summary","end-of-experiment.html#end-of-experiment","appendix-00.html#appendix","appendix-01-keywords.html#appendix-a-keywords","appendix-01-keywords.html#keywords-currently-in-use","appendix-01-keywords.html#keywords-reserved-for-future-use","appendix-01-keywords.html#raw-identifiers","appendix-02-operators.html#appendix-b-operators-and-symbols","appendix-02-operators.html#operators","appendix-02-operators.html#non-operator-symbols","appendix-03-derivable-traits.html#appendix-c-derivable-traits","appendix-03-derivable-traits.html#debug-for-programmer-output","appendix-03-derivable-traits.html#partialeq-and-eq-for-equality-comparisons","appendix-03-derivable-traits.html#partialord-and-ord-for-ordering-comparisons","appendix-03-derivable-traits.html#clone-and-copy-for-duplicating-values","appendix-03-derivable-traits.html#hash-for-mapping-a-value-to-a-value-of-fixed-size","appendix-03-derivable-traits.html#default-for-default-values","appendix-04-useful-development-tools.html#appendix-d---useful-development-tools","appendix-04-useful-development-tools.html#automatic-formatting-with-rustfmt","appendix-04-useful-development-tools.html#fix-your-code-with-rustfix","appendix-04-useful-development-tools.html#more-lints-with-clippy","appendix-04-useful-development-tools.html#ide-integration-using-rust-analyzer","appendix-05-editions.html#appendix-e---editions","appendix-06-translation.html#appendix-f-translations-of-the-book","appendix-07-nightly-rust.html#appendix-g---how-rust-is-made-and-nightly-rust","appendix-07-nightly-rust.html#stability-without-stagnation","appendix-07-nightly-rust.html#choo-choo-release-channels-and-riding-the-trains","appendix-07-nightly-rust.html#maintenance-time","appendix-07-nightly-rust.html#unstable-features","appendix-07-nightly-rust.html#rustup-and-the-role-of-rust-nightly","appendix-07-nightly-rust.html#the-rfc-process-and-teams"],"index":{"documentStore":{"docInfo":{"0":{"body":12,"breadcrumbs":4,"title":2},"1":{"body":71,"breadcrumbs":4,"title":2},"10":{"body":41,"breadcrumbs":2,"title":1},"100":{"body":63,"breadcrumbs":5,"title":1},"101":{"body":33,"breadcrumbs":5,"title":1},"102":{"body":39,"breadcrumbs":6,"title":2},"103":{"body":471,"breadcrumbs":8,"title":4},"104":{"body":332,"breadcrumbs":6,"title":2},"105":{"body":75,"breadcrumbs":6,"title":2},"106":{"body":81,"breadcrumbs":10,"title":5},"107":{"body":333,"breadcrumbs":11,"title":3},"108":{"body":106,"breadcrumbs":12,"title":4},"109":{"body":221,"breadcrumbs":14,"title":6},"11":{"body":38,"breadcrumbs":2,"title":1},"110":{"body":120,"breadcrumbs":17,"title":9},"111":{"body":100,"breadcrumbs":12,"title":4},"112":{"body":191,"breadcrumbs":11,"title":3},"113":{"body":94,"breadcrumbs":11,"title":3},"114":{"body":190,"breadcrumbs":13,"title":4},"115":{"body":108,"breadcrumbs":11,"title":2},"116":{"body":166,"breadcrumbs":14,"title":5},"117":{"body":633,"breadcrumbs":14,"title":5},"118":{"body":43,"breadcrumbs":9,"title":2},"119":{"body":405,"breadcrumbs":9,"title":2},"12":{"body":16,"breadcrumbs":4,"title":3},"120":{"body":273,"breadcrumbs":10,"title":3},"121":{"body":146,"breadcrumbs":9,"title":2},"122":{"body":108,"breadcrumbs":10,"title":3},"123":{"body":254,"breadcrumbs":13,"title":6},"124":{"body":462,"breadcrumbs":9,"title":2},"125":{"body":49,"breadcrumbs":8,"title":1},"126":{"body":62,"breadcrumbs":6,"title":3},"127":{"body":154,"breadcrumbs":7,"title":2},"128":{"body":625,"breadcrumbs":7,"title":2},"129":{"body":642,"breadcrumbs":11,"title":6},"13":{"body":94,"breadcrumbs":5,"title":4},"130":{"body":337,"breadcrumbs":11,"title":4},"131":{"body":203,"breadcrumbs":10,"title":3},"132":{"body":265,"breadcrumbs":9,"title":2},"133":{"body":162,"breadcrumbs":9,"title":2},"134":{"body":302,"breadcrumbs":11,"title":4},"135":{"body":98,"breadcrumbs":10,"title":3},"136":{"body":286,"breadcrumbs":9,"title":3},"137":{"body":82,"breadcrumbs":7,"title":1},"138":{"body":23,"breadcrumbs":9,"title":3},"139":{"body":147,"breadcrumbs":10,"title":4},"14":{"body":42,"breadcrumbs":2,"title":1},"140":{"body":0,"breadcrumbs":7,"title":1},"141":{"body":252,"breadcrumbs":12,"title":6},"142":{"body":340,"breadcrumbs":10,"title":2},"143":{"body":29,"breadcrumbs":16,"title":5},"144":{"body":281,"breadcrumbs":14,"title":3},"145":{"body":346,"breadcrumbs":15,"title":4},"146":{"body":539,"breadcrumbs":16,"title":5},"147":{"body":502,"breadcrumbs":15,"title":4},"148":{"body":141,"breadcrumbs":15,"title":4},"149":{"body":315,"breadcrumbs":15,"title":4},"15":{"body":503,"breadcrumbs":3,"title":2},"150":{"body":265,"breadcrumbs":16,"title":5},"151":{"body":249,"breadcrumbs":15,"title":4},"152":{"body":88,"breadcrumbs":15,"title":4},"153":{"body":180,"breadcrumbs":16,"title":5},"154":{"body":161,"breadcrumbs":14,"title":3},"155":{"body":273,"breadcrumbs":19,"title":8},"156":{"body":68,"breadcrumbs":13,"title":2},"157":{"body":284,"breadcrumbs":14,"title":4},"158":{"body":148,"breadcrumbs":13,"title":3},"159":{"body":54,"breadcrumbs":11,"title":1},"16":{"body":6,"breadcrumbs":3,"title":2},"160":{"body":123,"breadcrumbs":4,"title":2},"161":{"body":38,"breadcrumbs":10,"title":4},"162":{"body":171,"breadcrumbs":9,"title":3},"163":{"body":54,"breadcrumbs":8,"title":2},"164":{"body":453,"breadcrumbs":9,"title":3},"165":{"body":131,"breadcrumbs":10,"title":4},"166":{"body":177,"breadcrumbs":9,"title":3},"167":{"body":195,"breadcrumbs":11,"title":5},"168":{"body":58,"breadcrumbs":10,"title":4},"169":{"body":88,"breadcrumbs":14,"title":6},"17":{"body":30,"breadcrumbs":4,"title":2},"170":{"body":90,"breadcrumbs":9,"title":1},"171":{"body":215,"breadcrumbs":11,"title":3},"172":{"body":489,"breadcrumbs":10,"title":2},"173":{"body":501,"breadcrumbs":10,"title":2},"174":{"body":120,"breadcrumbs":10,"title":2},"175":{"body":88,"breadcrumbs":12,"title":4},"176":{"body":93,"breadcrumbs":10,"title":2},"177":{"body":105,"breadcrumbs":14,"title":6},"178":{"body":109,"breadcrumbs":12,"title":4},"179":{"body":108,"breadcrumbs":12,"title":4},"18":{"body":77,"breadcrumbs":4,"title":1},"180":{"body":97,"breadcrumbs":11,"title":3},"181":{"body":469,"breadcrumbs":11,"title":3},"182":{"body":71,"breadcrumbs":10,"title":2},"183":{"body":131,"breadcrumbs":9,"title":1},"184":{"body":16,"breadcrumbs":8,"title":3},"185":{"body":130,"breadcrumbs":4,"title":2},"186":{"body":60,"breadcrumbs":8,"title":3},"187":{"body":626,"breadcrumbs":10,"title":5},"188":{"body":392,"breadcrumbs":8,"title":3},"189":{"body":497,"breadcrumbs":8,"title":3},"19":{"body":38,"breadcrumbs":6,"title":3},"190":{"body":1435,"breadcrumbs":7,"title":2},"191":{"body":100,"breadcrumbs":6,"title":2},"192":{"body":81,"breadcrumbs":8,"title":4},"193":{"body":159,"breadcrumbs":8,"title":4},"194":{"body":335,"breadcrumbs":7,"title":3},"195":{"body":467,"breadcrumbs":8,"title":4},"196":{"body":81,"breadcrumbs":5,"title":1},"197":{"body":153,"breadcrumbs":8,"title":4},"198":{"body":459,"breadcrumbs":8,"title":4},"199":{"body":30,"breadcrumbs":10,"title":3},"2":{"body":53,"breadcrumbs":4,"title":2},"20":{"body":94,"breadcrumbs":7,"title":4},"200":{"body":484,"breadcrumbs":9,"title":2},"201":{"body":322,"breadcrumbs":9,"title":2},"202":{"body":159,"breadcrumbs":9,"title":2},"203":{"body":467,"breadcrumbs":9,"title":2},"204":{"body":180,"breadcrumbs":11,"title":4},"205":{"body":32,"breadcrumbs":12,"title":4},"206":{"body":194,"breadcrumbs":10,"title":2},"207":{"body":341,"breadcrumbs":11,"title":3},"208":{"body":399,"breadcrumbs":10,"title":2},"209":{"body":430,"breadcrumbs":10,"title":2},"21":{"body":43,"breadcrumbs":6,"title":3},"210":{"body":302,"breadcrumbs":12,"title":4},"211":{"body":264,"breadcrumbs":14,"title":6},"212":{"body":94,"breadcrumbs":10,"title":3},"213":{"body":243,"breadcrumbs":11,"title":4},"214":{"body":151,"breadcrumbs":13,"title":6},"215":{"body":298,"breadcrumbs":10,"title":3},"216":{"body":120,"breadcrumbs":10,"title":3},"217":{"body":620,"breadcrumbs":11,"title":4},"218":{"body":267,"breadcrumbs":10,"title":3},"219":{"body":129,"breadcrumbs":11,"title":4},"22":{"body":77,"breadcrumbs":4,"title":1},"220":{"body":590,"breadcrumbs":9,"title":2},"221":{"body":209,"breadcrumbs":11,"title":4},"222":{"body":82,"breadcrumbs":9,"title":2},"223":{"body":101,"breadcrumbs":14,"title":7},"224":{"body":102,"breadcrumbs":8,"title":1},"225":{"body":16,"breadcrumbs":10,"title":3},"226":{"body":175,"breadcrumbs":6,"title":3},"227":{"body":46,"breadcrumbs":7,"title":2},"228":{"body":868,"breadcrumbs":8,"title":3},"229":{"body":640,"breadcrumbs":9,"title":4},"23":{"body":28,"breadcrumbs":5,"title":2},"230":{"body":504,"breadcrumbs":10,"title":5},"231":{"body":355,"breadcrumbs":9,"title":4},"232":{"body":667,"breadcrumbs":8,"title":3},"233":{"body":136,"breadcrumbs":9,"title":4},"234":{"body":92,"breadcrumbs":9,"title":3},"235":{"body":158,"breadcrumbs":10,"title":4},"236":{"body":318,"breadcrumbs":9,"title":3},"237":{"body":353,"breadcrumbs":10,"title":4},"238":{"body":253,"breadcrumbs":11,"title":5},"239":{"body":69,"breadcrumbs":7,"title":2},"24":{"body":32,"breadcrumbs":5,"title":2},"240":{"body":301,"breadcrumbs":7,"title":2},"241":{"body":892,"breadcrumbs":7,"title":2},"242":{"body":76,"breadcrumbs":6,"title":1},"243":{"body":221,"breadcrumbs":12,"title":6},"244":{"body":87,"breadcrumbs":14,"title":4},"245":{"body":142,"breadcrumbs":13,"title":3},"246":{"body":191,"breadcrumbs":14,"title":4},"247":{"body":163,"breadcrumbs":14,"title":4},"248":{"body":281,"breadcrumbs":10,"title":2},"249":{"body":197,"breadcrumbs":16,"title":5},"25":{"body":80,"breadcrumbs":6,"title":2},"250":{"body":527,"breadcrumbs":15,"title":4},"251":{"body":289,"breadcrumbs":15,"title":4},"252":{"body":794,"breadcrumbs":14,"title":3},"253":{"body":660,"breadcrumbs":14,"title":3},"254":{"body":263,"breadcrumbs":15,"title":4},"255":{"body":126,"breadcrumbs":18,"title":6},"256":{"body":571,"breadcrumbs":15,"title":3},"257":{"body":856,"breadcrumbs":16,"title":4},"258":{"body":42,"breadcrumbs":12,"title":3},"259":{"body":269,"breadcrumbs":16,"title":7},"26":{"body":63,"breadcrumbs":7,"title":3},"260":{"body":1185,"breadcrumbs":12,"title":3},"261":{"body":47,"breadcrumbs":22,"title":8},"262":{"body":146,"breadcrumbs":17,"title":3},"263":{"body":153,"breadcrumbs":18,"title":4},"264":{"body":59,"breadcrumbs":15,"title":1},"265":{"body":102,"breadcrumbs":10,"title":5},"266":{"body":36,"breadcrumbs":15,"title":5},"267":{"body":387,"breadcrumbs":13,"title":3},"268":{"body":479,"breadcrumbs":14,"title":4},"269":{"body":515,"breadcrumbs":14,"title":4},"27":{"body":113,"breadcrumbs":8,"title":4},"270":{"body":749,"breadcrumbs":17,"title":7},"271":{"body":304,"breadcrumbs":14,"title":4},"272":{"body":211,"breadcrumbs":13,"title":4},"273":{"body":216,"breadcrumbs":13,"title":4},"274":{"body":117,"breadcrumbs":12,"title":3},"275":{"body":273,"breadcrumbs":12,"title":3},"276":{"body":203,"breadcrumbs":13,"title":4},"277":{"body":25,"breadcrumbs":11,"title":3},"278":{"body":870,"breadcrumbs":12,"title":4},"279":{"body":364,"breadcrumbs":13,"title":5},"28":{"body":190,"breadcrumbs":7,"title":3},"280":{"body":81,"breadcrumbs":12,"title":4},"281":{"body":377,"breadcrumbs":15,"title":5},"282":{"body":50,"breadcrumbs":11,"title":1},"283":{"body":51,"breadcrumbs":6,"title":3},"284":{"body":266,"breadcrumbs":11,"title":4},"285":{"body":40,"breadcrumbs":9,"title":3},"286":{"body":538,"breadcrumbs":10,"title":4},"287":{"body":615,"breadcrumbs":12,"title":6},"288":{"body":69,"breadcrumbs":10,"title":4},"289":{"body":293,"breadcrumbs":10,"title":4},"29":{"body":204,"breadcrumbs":8,"title":4},"290":{"body":107,"breadcrumbs":8,"title":2},"291":{"body":35,"breadcrumbs":11,"title":5},"292":{"body":124,"breadcrumbs":11,"title":5},"293":{"body":35,"breadcrumbs":7,"title":2},"294":{"body":196,"breadcrumbs":7,"title":2},"295":{"body":842,"breadcrumbs":9,"title":4},"296":{"body":171,"breadcrumbs":12,"title":4},"297":{"body":41,"breadcrumbs":11,"title":4},"298":{"body":36,"breadcrumbs":8,"title":1},"299":{"body":286,"breadcrumbs":4,"title":2},"3":{"body":82,"breadcrumbs":4,"title":2},"30":{"body":118,"breadcrumbs":6,"title":2},"300":{"body":149,"breadcrumbs":12,"title":5},"301":{"body":119,"breadcrumbs":12,"title":5},"302":{"body":979,"breadcrumbs":11,"title":4},"303":{"body":103,"breadcrumbs":16,"title":7},"304":{"body":170,"breadcrumbs":12,"title":3},"305":{"body":90,"breadcrumbs":12,"title":3},"306":{"body":216,"breadcrumbs":12,"title":3},"307":{"body":281,"breadcrumbs":15,"title":6},"308":{"body":374,"breadcrumbs":14,"title":5},"309":{"body":135,"breadcrumbs":13,"title":4},"31":{"body":326,"breadcrumbs":7,"title":3},"310":{"body":341,"breadcrumbs":12,"title":5},"311":{"body":454,"breadcrumbs":11,"title":4},"312":{"body":159,"breadcrumbs":12,"title":5},"313":{"body":416,"breadcrumbs":11,"title":4},"314":{"body":277,"breadcrumbs":12,"title":5},"315":{"body":87,"breadcrumbs":10,"title":4},"316":{"body":265,"breadcrumbs":11,"title":5},"317":{"body":1492,"breadcrumbs":12,"title":6},"318":{"body":290,"breadcrumbs":14,"title":8},"319":{"body":59,"breadcrumbs":10,"title":4},"32":{"body":334,"breadcrumbs":8,"title":4},"320":{"body":585,"breadcrumbs":9,"title":3},"321":{"body":926,"breadcrumbs":12,"title":6},"322":{"body":100,"breadcrumbs":7,"title":1},"323":{"body":279,"breadcrumbs":4,"title":2},"324":{"body":169,"breadcrumbs":12,"title":5},"325":{"body":201,"breadcrumbs":11,"title":4},"326":{"body":336,"breadcrumbs":13,"title":6},"327":{"body":582,"breadcrumbs":11,"title":4},"328":{"body":590,"breadcrumbs":16,"title":7},"329":{"body":228,"breadcrumbs":12,"title":3},"33":{"body":62,"breadcrumbs":6,"title":2},"330":{"body":154,"breadcrumbs":15,"title":6},"331":{"body":158,"breadcrumbs":14,"title":5},"332":{"body":104,"breadcrumbs":8,"title":3},"333":{"body":1091,"breadcrumbs":13,"title":8},"334":{"body":119,"breadcrumbs":9,"title":4},"335":{"body":40,"breadcrumbs":12,"title":5},"336":{"body":96,"breadcrumbs":13,"title":6},"337":{"body":135,"breadcrumbs":12,"title":5},"338":{"body":65,"breadcrumbs":12,"title":5},"339":{"body":114,"breadcrumbs":8,"title":1},"34":{"body":73,"breadcrumbs":6,"title":2},"340":{"body":336,"breadcrumbs":4,"title":2},"341":{"body":309,"breadcrumbs":4,"title":2},"342":{"body":209,"breadcrumbs":8,"title":3},"343":{"body":1503,"breadcrumbs":8,"title":3},"344":{"body":54,"breadcrumbs":6,"title":2},"345":{"body":687,"breadcrumbs":5,"title":1},"346":{"body":1051,"breadcrumbs":6,"title":2},"347":{"body":1303,"breadcrumbs":8,"title":3},"348":{"body":308,"breadcrumbs":7,"title":2},"349":{"body":718,"breadcrumbs":6,"title":1},"35":{"body":70,"breadcrumbs":5,"title":1},"350":{"body":444,"breadcrumbs":8,"title":3},"351":{"body":504,"breadcrumbs":4,"title":1},"352":{"body":678,"breadcrumbs":5,"title":2},"353":{"body":1024,"breadcrumbs":5,"title":2},"354":{"body":50,"breadcrumbs":8,"title":3},"355":{"body":310,"breadcrumbs":6,"title":1},"356":{"body":819,"breadcrumbs":9,"title":4},"357":{"body":355,"breadcrumbs":7,"title":2},"358":{"body":713,"breadcrumbs":8,"title":3},"359":{"body":74,"breadcrumbs":6,"title":1},"36":{"body":81,"breadcrumbs":6,"title":3},"360":{"body":77,"breadcrumbs":10,"title":5},"361":{"body":43,"breadcrumbs":13,"title":4},"362":{"body":81,"breadcrumbs":13,"title":4},"363":{"body":351,"breadcrumbs":13,"title":4},"364":{"body":156,"breadcrumbs":14,"title":5},"365":{"body":118,"breadcrumbs":10,"title":1},"366":{"body":212,"breadcrumbs":19,"title":7},"367":{"body":423,"breadcrumbs":16,"title":4},"368":{"body":206,"breadcrumbs":14,"title":2},"369":{"body":327,"breadcrumbs":14,"title":2},"37":{"body":130,"breadcrumbs":7,"title":4},"370":{"body":192,"breadcrumbs":16,"title":4},"371":{"body":133,"breadcrumbs":17,"title":5},"372":{"body":368,"breadcrumbs":15,"title":5},"373":{"body":169,"breadcrumbs":17,"title":7},"374":{"body":131,"breadcrumbs":14,"title":4},"375":{"body":129,"breadcrumbs":15,"title":5},"376":{"body":314,"breadcrumbs":15,"title":5},"377":{"body":720,"breadcrumbs":15,"title":5},"378":{"body":967,"breadcrumbs":14,"title":4},"379":{"body":77,"breadcrumbs":11,"title":1},"38":{"body":226,"breadcrumbs":5,"title":2},"380":{"body":16,"breadcrumbs":11,"title":3},"381":{"body":279,"breadcrumbs":11,"title":3},"382":{"body":8,"breadcrumbs":9,"title":1},"383":{"body":5,"breadcrumbs":10,"title":2},"384":{"body":7,"breadcrumbs":9,"title":1},"385":{"body":3,"breadcrumbs":9,"title":1},"386":{"body":133,"breadcrumbs":4,"title":2},"387":{"body":16,"breadcrumbs":8,"title":3},"388":{"body":129,"breadcrumbs":7,"title":2},"389":{"body":240,"breadcrumbs":7,"title":2},"39":{"body":210,"breadcrumbs":6,"title":3},"390":{"body":82,"breadcrumbs":7,"title":2},"391":{"body":101,"breadcrumbs":6,"title":1},"392":{"body":292,"breadcrumbs":6,"title":1},"393":{"body":135,"breadcrumbs":7,"title":2},"394":{"body":454,"breadcrumbs":12,"title":5},"395":{"body":10,"breadcrumbs":6,"title":2},"396":{"body":42,"breadcrumbs":6,"title":2},"397":{"body":256,"breadcrumbs":7,"title":3},"398":{"body":47,"breadcrumbs":6,"title":2},"399":{"body":119,"breadcrumbs":7,"title":3},"4":{"body":24,"breadcrumbs":4,"title":2},"40":{"body":177,"breadcrumbs":6,"title":3},"400":{"body":783,"breadcrumbs":8,"title":4},"401":{"body":821,"breadcrumbs":7,"title":3},"402":{"body":457,"breadcrumbs":8,"title":4},"403":{"body":188,"breadcrumbs":5,"title":1},"404":{"body":56,"breadcrumbs":5,"title":1},"405":{"body":111,"breadcrumbs":4,"title":2},"406":{"body":138,"breadcrumbs":6,"title":2},"407":{"body":206,"breadcrumbs":6,"title":2},"408":{"body":408,"breadcrumbs":7,"title":3},"409":{"body":1044,"breadcrumbs":8,"title":4},"41":{"body":282,"breadcrumbs":7,"title":4},"410":{"body":241,"breadcrumbs":9,"title":5},"411":{"body":124,"breadcrumbs":7,"title":3},"412":{"body":44,"breadcrumbs":7,"title":3},"413":{"body":38,"breadcrumbs":7,"title":3},"414":{"body":21,"breadcrumbs":6,"title":2},"415":{"body":339,"breadcrumbs":11,"title":7},"416":{"body":427,"breadcrumbs":10,"title":6},"417":{"body":847,"breadcrumbs":12,"title":8},"418":{"body":432,"breadcrumbs":13,"title":9},"419":{"body":251,"breadcrumbs":12,"title":8},"42":{"body":109,"breadcrumbs":7,"title":4},"420":{"body":34,"breadcrumbs":6,"title":2},"421":{"body":141,"breadcrumbs":10,"title":6},"422":{"body":451,"breadcrumbs":9,"title":5},"423":{"body":339,"breadcrumbs":8,"title":4},"424":{"body":377,"breadcrumbs":9,"title":5},"425":{"body":12,"breadcrumbs":8,"title":3},"426":{"body":382,"breadcrumbs":7,"title":2},"427":{"body":170,"breadcrumbs":7,"title":2},"428":{"body":63,"breadcrumbs":4,"title":1},"429":{"body":142,"breadcrumbs":7,"title":4},"43":{"body":42,"breadcrumbs":6,"title":3},"430":{"body":477,"breadcrumbs":8,"title":5},"431":{"body":151,"breadcrumbs":8,"title":5},"432":{"body":1035,"breadcrumbs":7,"title":4},"433":{"body":103,"breadcrumbs":5,"title":2},"434":{"body":96,"breadcrumbs":5,"title":2},"435":{"body":46,"breadcrumbs":4,"title":1},"436":{"body":150,"breadcrumbs":12,"title":6},"437":{"body":108,"breadcrumbs":16,"title":5},"438":{"body":468,"breadcrumbs":14,"title":3},"439":{"body":363,"breadcrumbs":13,"title":2},"44":{"body":41,"breadcrumbs":6,"title":3},"440":{"body":173,"breadcrumbs":15,"title":4},"441":{"body":220,"breadcrumbs":13,"title":2},"442":{"body":233,"breadcrumbs":14,"title":3},"443":{"body":367,"breadcrumbs":15,"title":4},"444":{"body":213,"breadcrumbs":13,"title":2},"445":{"body":53,"breadcrumbs":18,"title":6},"446":{"body":214,"breadcrumbs":18,"title":6},"447":{"body":3570,"breadcrumbs":16,"title":4},"448":{"body":86,"breadcrumbs":12,"title":3},"449":{"body":815,"breadcrumbs":13,"title":4},"45":{"body":630,"breadcrumbs":7,"title":4},"450":{"body":963,"breadcrumbs":14,"title":5},"451":{"body":31,"breadcrumbs":10,"title":1},"452":{"body":21,"breadcrumbs":4,"title":2},"453":{"body":9,"breadcrumbs":2,"title":1},"454":{"body":38,"breadcrumbs":4,"title":2},"455":{"body":213,"breadcrumbs":5,"title":3},"456":{"body":20,"breadcrumbs":6,"title":4},"457":{"body":173,"breadcrumbs":4,"title":2},"458":{"body":20,"breadcrumbs":8,"title":4},"459":{"body":314,"breadcrumbs":5,"title":1},"46":{"body":277,"breadcrumbs":6,"title":3},"460":{"body":537,"breadcrumbs":7,"title":3},"461":{"body":168,"breadcrumbs":8,"title":4},"462":{"body":50,"breadcrumbs":7,"title":3},"463":{"body":103,"breadcrumbs":8,"title":4},"464":{"body":159,"breadcrumbs":8,"title":4},"465":{"body":174,"breadcrumbs":8,"title":4},"466":{"body":49,"breadcrumbs":10,"title":6},"467":{"body":80,"breadcrumbs":7,"title":3},"468":{"body":20,"breadcrumbs":10,"title":5},"469":{"body":67,"breadcrumbs":8,"title":3},"47":{"body":859,"breadcrumbs":7,"title":4},"470":{"body":149,"breadcrumbs":8,"title":3},"471":{"body":131,"breadcrumbs":8,"title":3},"472":{"body":59,"breadcrumbs":10,"title":5},"473":{"body":298,"breadcrumbs":6,"title":3},"474":{"body":28,"breadcrumbs":8,"title":4},"475":{"body":6,"breadcrumbs":12,"title":6},"476":{"body":57,"breadcrumbs":9,"title":3},"477":{"body":326,"breadcrumbs":12,"title":6},"478":{"body":22,"breadcrumbs":8,"title":2},"479":{"body":110,"breadcrumbs":8,"title":2},"48":{"body":215,"breadcrumbs":7,"title":4},"480":{"body":122,"breadcrumbs":10,"title":4},"481":{"body":132,"breadcrumbs":9,"title":3},"49":{"body":83,"breadcrumbs":6,"title":3},"5":{"body":62,"breadcrumbs":6,"title":3},"50":{"body":370,"breadcrumbs":6,"title":3},"51":{"body":56,"breadcrumbs":4,"title":1},"52":{"body":87,"breadcrumbs":6,"title":3},"53":{"body":366,"breadcrumbs":7,"title":2},"54":{"body":206,"breadcrumbs":6,"title":1},"55":{"body":312,"breadcrumbs":6,"title":1},"56":{"body":146,"breadcrumbs":7,"title":2},"57":{"body":769,"breadcrumbs":7,"title":2},"58":{"body":703,"breadcrumbs":7,"title":2},"59":{"body":164,"breadcrumbs":5,"title":1},"6":{"body":226,"breadcrumbs":2,"title":1},"60":{"body":228,"breadcrumbs":5,"title":1},"61":{"body":330,"breadcrumbs":6,"title":2},"62":{"body":303,"breadcrumbs":7,"title":3},"63":{"body":142,"breadcrumbs":5,"title":1},"64":{"body":26,"breadcrumbs":7,"title":2},"65":{"body":648,"breadcrumbs":6,"title":1},"66":{"body":884,"breadcrumbs":7,"title":2},"67":{"body":55,"breadcrumbs":6,"title":1},"68":{"body":38,"breadcrumbs":4,"title":2},"69":{"body":16,"breadcrumbs":4,"title":1},"7":{"body":66,"breadcrumbs":2,"title":1},"70":{"body":443,"breadcrumbs":7,"title":4},"71":{"body":124,"breadcrumbs":7,"title":4},"72":{"body":157,"breadcrumbs":6,"title":3},"73":{"body":110,"breadcrumbs":6,"title":3},"74":{"body":163,"breadcrumbs":8,"title":5},"75":{"body":172,"breadcrumbs":7,"title":4},"76":{"body":92,"breadcrumbs":6,"title":3},"77":{"body":179,"breadcrumbs":7,"title":4},"78":{"body":45,"breadcrumbs":6,"title":3},"79":{"body":102,"breadcrumbs":4,"title":1},"8":{"body":11,"breadcrumbs":2,"title":1},"80":{"body":88,"breadcrumbs":6,"title":2},"81":{"body":88,"breadcrumbs":8,"title":4},"82":{"body":226,"breadcrumbs":8,"title":4},"83":{"body":318,"breadcrumbs":9,"title":5},"84":{"body":291,"breadcrumbs":8,"title":4},"85":{"body":170,"breadcrumbs":9,"title":5},"86":{"body":193,"breadcrumbs":12,"title":8},"87":{"body":91,"breadcrumbs":9,"title":5},"88":{"body":316,"breadcrumbs":7,"title":3},"89":{"body":82,"breadcrumbs":5,"title":1},"9":{"body":109,"breadcrumbs":3,"title":2},"90":{"body":61,"breadcrumbs":8,"title":3},"91":{"body":208,"breadcrumbs":11,"title":6},"92":{"body":242,"breadcrumbs":10,"title":5},"93":{"body":178,"breadcrumbs":12,"title":7},"94":{"body":322,"breadcrumbs":13,"title":8},"95":{"body":223,"breadcrumbs":12,"title":7},"96":{"body":235,"breadcrumbs":12,"title":7},"97":{"body":43,"breadcrumbs":6,"title":1},"98":{"body":415,"breadcrumbs":6,"title":2},"99":{"body":734,"breadcrumbs":6,"title":2}},"docs":{"0":{"body":"Welcome to the Rust Book experiment, and thank you for your participation! First, we want to introduce you to the new mechanics of this experiment.","breadcrumbs":"Experiment Introduction » Experiment Introduction","id":"0","title":"Experiment Introduction"},"1":{"body":"The main mechanic is quizzes : each page has a few quizzes about the page’s content. We have two rules about quizzes for this experiment: Take a quiz as soon as you get to it. Do not skip a quiz. (We don’t enforce these rules, but please follow them!) Every quiz looks like the one below. Try it out by clicking “Start”. If you get a question incorrect, you can choose to either retry the quiz, or see the correct answers. We encourage you to retry the quiz until you get 100% — feel free to review the content before retrying the quiz. Note that once you see the correct answers, you cannot retry the quiz. If you spot an issue in a quiz or other part of the book, you can file an issue on our Github repository: https://github.com/cognitive-engineering-lab/rust-book","breadcrumbs":"Experiment Introduction » 1. Quizzes","id":"1","title":"1. Quizzes"},"10":{"body":"Rust is for students and those who are interested in learning about systems concepts. Using Rust, many people have learned about topics like operating systems development. The community is very welcoming and happy to answer student questions. Through efforts such as this book, the Rust teams want to make systems concepts more accessible to more people, especially those new to programming.","breadcrumbs":"Introduction » Students","id":"10","title":"Students"},"100":{"body":"String slices, as you might imagine, are specific to strings. But there’s a more general slice type, too. Consider this array: let a = [1, 2, 3, 4, 5]; Just as we might want to refer to a part of a string, we might want to refer to part of an array. We’d do so like this: let a = [1, 2, 3, 4, 5]; let slice = &a[1..3]; assert_eq!(slice, &[2, 3]); This slice has the type &[i32]. It works the same way as string slices do, by storing a reference to the first element and a length. You’ll use this kind of slice for all sorts of other collections. We’ll discuss these collections in detail when we talk about vectors in Chapter 8.","breadcrumbs":"Understanding Ownership » The Slice Type » Other Slices","id":"100","title":"Other Slices"},"101":{"body":"Slices are a special kind of reference that refer to sub-ranges of a sequence, like a string or a vector. At runtime, a slice is represented as a “fat pointer” which contains a pointer to the beginning of the range and a length of the range. One advantage of slices over index-based ranges is that the slice cannot be invalidated while it’s being used.","breadcrumbs":"Understanding Ownership » The Slice Type » Summary","id":"101","title":"Summary"},"102":{"body":"This chapter introduced a lot of new concepts like ownership, borrowing, and slices. If you aren’t familiar with systems programming, this chapter also introduced new concepts like memory allocation, the stack vs. the heap, pointers, and undefined behavior. Before we move on to the rest of Rust, let’s first stop and take a breath. We’ll review and practice with the key concepts from this chapter.","breadcrumbs":"Understanding Ownership » Ownership Recap » Ownership Recap","id":"102","title":"Ownership Recap"},"103":{"body":"To put ownership into context, we should talk about garbage collection . Most programming languages use a garbage collector to manage memory, such as in Python, Javascript, Java, and Go. A garbage collector works at runtime adjacent to a running program (a tracing collector, at least). The collector scans through memory to find data that’s no longer used — that is, the running program can no longer reach that data from a function-local variable. Then the collector deallocates the unused memory for later use. The key benefit of a garbage collector is that it avoids undefined behavior (such as using freed memory), as can happen in C or C++. Garbage collection also avoids the need for a complex type system to check for undefined behavior, like in Rust. However, there are a few drawbacks to garbage collection. One obvious drawback is performance, as garbage collection incurs either frequent small overheads (for reference-counting, like in Python and Swift) or infrequent large overheads (for tracing, like in all other GC’d languages). But another less obvious drawback is that garbage collection can be unpredictable . To illustrate the point, say we are implementing a Document type that represents a mutable list of words. We could implement Document in a garbage-collected language such as Python in this way: class Document: def __init__(self, words: List[str]): \"\"\"Create a new document\"\"\" self.words = words def add_word(self, word: str): \"\"\"Add a word to the document\"\"\" self.words.append(word) def get_words(self) -> List[str]: \"\"\"Get a list of all the words in the document\"\"\" return self.words Here’s one way we could use this Document class that creates a document d, copies it into a new document d2, and then mutates d2. words = [\"Hello\"]\nd = Document(words) d2 = Document(d.get_words())\nd2.add_word(\"world\") Consider two key questions about this example: When is the words array deallocated? This program has created three pointers to the same array. The variables words, d, and d2 all contain a pointer to the words array allocated on the heap. Therefore Python will only deallocate the words array when all three variables are out of scope. More generally, it’s often difficult to predict where data will be garbage-collected just by reading the source code. What are the contents of the document d? Because d2 contains a pointer to the same words array as d, then d2.add_word(\"world\") also mutates the document d. Therefore in this example, the words in d are [\"Hello\", \"world\"]. This happens because d.get_words() returns a mutable reference to the words array in d. Pervasive, implicit mutable references can easily lead to unpredictable bugs when data structures can leak their internals [1] . Here, it is probably not intended behavior that a change to d2 can change d. This problem is not unique to Python — you can encounter similar behavior in C#, Java, Javascript, and so on. In fact, most programming languages actually have a concept of pointers. It’s just a question of how the language exposes pointers to the programmer. Garbage collection makes it difficult to see which variable points to which data. For example, it wasn’t obvious that d.get_words() produced a pointer to data within d. By contrast, Rust’s ownership model puts pointers front-and-center. We can see that by translating the Document type into a Rust data structure. Normally we would use a struct, but we haven’t covered those yet, so we’ll just use a type alias: type Document = Vec; fn new_document(words: Vec) -> Document { words\n} fn add_word(this: &mut Document, word: String) { this.push(word);\n} fn get_words(this: &Document) -> &[String] { this.as_slice()\n} This Rust API differs from the Python API in a few key ways: The function new_document consumes ownership of the input vector words. That means the Document owns the word vector. The word vector will be predictably deallocated when its owning Document goes out of scope. The function add_word requires a mutable reference &mut Document to be able to mutate a document. It also consumes ownership of the input word, meaning no one else can mutate the individual words of the document. The function get_words returns an explicit immutable reference to strings within the document. The only way to create a new document from this word vector is to deep-copy its contents, like this: fn main() { let words = vec![\"hello\".to_string()]; let d = new_document(words); // .to_vec() converts &[String] to Vec by cloning each string let words_copy = get_words(&d).to_vec(); let mut d2 = new_document(words_copy); add_word(&mut d2, \"world\".to_string()); // The modification to `d2` does not affect `d` assert!(!get_words(&d).contains(&\"world\".into()));\n} The point of this example is to say: if Rust is not your first language, then you already have experience working with memory and pointers! Rust just makes those concepts explicit. This has the dual benefit of (1) improving runtime performance by avoiding garbage collection, and (2) improving predictability by preventing accidental “leaks” of data.","breadcrumbs":"Understanding Ownership » Ownership Recap » Ownership versus Garbage Collection","id":"103","title":"Ownership versus Garbage Collection"},"104":{"body":"Next, let’s review the concepts of ownership. This review will be quick — the goal is to remind you of the relevant concepts. If you realize you forgot or didn’t understand a concept, then we will link you to the relevant chapters which you can review. Ownership at Runtime We’ll start by reviewing how Rust uses memory at runtime: Rust allocates local variables in stack frames, which are allocated when a function is called and deallocated when the call ends. Local variables can hold either data (like numbers, booleans, tuples, etc.) or pointers. Pointers can be created either through boxes (pointers owning data on the heap) or references (non-owning pointers). This diagram illustrates how each concept looks at runtime: Review this diagram and make sure you understand each part. For example, you should be able to answer: Why does a_box_stack_ref point to the stack, while a_box_heap_ref point to the heap? Why is the value 2 no longer on the heap at L2? Why does a_num have the value 5 at L2? If you want to review boxes, re-read Chapter 4.1 . If you want to review references, re-read Chapter 4.2 . If you want to see case studies involving boxes and references, re-read Chapter 4.3 . Slices are a special kind of reference that refer to a contiguous sequence of data in memory. This diagram illustrates how a slice refers to a subsequence of characters in a string: If you want to review slices, re-read Chapter 4.4 . Ownership at Compile-time Rust tracks R (read), W (write), and O (own) permissions on each variable. Rust requires that a variable has appropriate permissions to perform a given operation. As a basic example, if a variable is not declared as let mut, then it is missing the W permission and cannot be mutated: A variable’s permissions can be changed if it is moved or borrowed . A move of a variable with a non-copyable type (like Box or String) requires the RO permissions, and the move eliminates all permissions on the variable. That rule prevents the use of moved variables: If you want to review how moves work, re-read Chapter 4.1 . Borrowing a variable (creating a reference to it) temporarily removes some of the variable’s permissions. An immutable borrow creates an immutable reference, and also disables the borrowed data from being mutated or moved. For example, printing an immutable reference is ok: But mutating an immutable reference is not ok: And mutating the immutably borrowed data is not ok: And moving data out of the reference is not ok: A mutable borrow creates a mutable reference, which disables the borrowed data from being read, written, or moved. For example, mutating a mutable reference is ok: But accessing the mutably borrowed data is not ok: If you want to review permissions and references, re-read Chapter 4.2 . Connecting Ownership between Compile-time and Runtime Rust’s permissions are designed to prevent undefined behavior. For example, one kind of undefined behavior is a use-after-free where freed memory is read or written. Immutable borrows remove the W permission to avoid use-after-free, like in this case: Another kind of undefined behavior is a double-free where memory is freed twice. Dereferences of references to non-copyable data do not have the O permission to avoid double-frees, like in this case: If you want to review undefined behavior, re-read Chapter 4.1 and Chapter 4.3 .","breadcrumbs":"Understanding Ownership » Ownership Recap » The Concepts of Ownership","id":"104","title":"The Concepts of Ownership"},"105":{"body":"As we introduce additional features like structs, enums, and traits, those features will have specific interactions with ownership. This chapter provides the essential foundation for understanding those interactions — the concepts of memory, pointers, undefined behavior, and permissions will help us talk about the more advanced parts of Rust in future chapters. And don’t forget to take the quizzes if you want to check your understanding! In fact, the original invention of ownership types wasn’t about memory safety at all. It was about preventing leaks of mutable references to data structure internals in Java-like languages. If you’re curious to learn more about the history of ownership types, check out the paper “Ownership Types for Flexible Alias Protection” (Clarke et al. 1998).","breadcrumbs":"Understanding Ownership » Ownership Recap » The Rest of Ownership","id":"105","title":"The Rest of Ownership"},"106":{"body":"A struct , or structure , is a custom data type that lets you package together and name multiple related values that make up a meaningful group. If you’re familiar with an object-oriented language, a struct is like an object’s data attributes. In this chapter, we’ll compare and contrast tuples with structs to build on what you already know and demonstrate when structs are a better way to group data. We’ll demonstrate how to define and instantiate structs. We’ll discuss how to define associated functions, especially the kind of associated functions called methods , to specify behavior associated with a struct type. Structs and enums (discussed in Chapter 6) are the building blocks for creating new types in your program’s domain to take full advantage of Rust’s compile-time type checking.","breadcrumbs":"Using Structs to Structure Related Data » Using Structs to Structure Related Data","id":"106","title":"Using Structs to Structure Related Data"},"107":{"body":"Structs are similar to tuples, discussed in “The Tuple Type” section, in that both hold multiple related values. Like tuples, the pieces of a struct can be different types. Unlike with tuples, in a struct you’ll name each piece of data so it’s clear what the values mean. Adding these names means that structs are more flexible than tuples: you don’t have to rely on the order of the data to specify or access the values of an instance. To define a struct, we enter the keyword struct and name the entire struct. A struct’s name should describe the significance of the pieces of data being grouped together. Then, inside curly brackets, we define the names and types of the pieces of data, which we call fields . For example, Listing 5-1 shows a struct that stores information about a user account. Filename: src/main.rs struct User { active: bool, username: String, email: String, sign_in_count: u64,\n}\n# # fn main() {} Listing 5-1: A User struct definition To use a struct after we’ve defined it, we create an instance of that struct by specifying concrete values for each of the fields. We create an instance by stating the name of the struct and then add curly brackets containing key: value pairs, where the keys are the names of the fields and the values are the data we want to store in those fields. We don’t have to specify the fields in the same order in which we declared them in the struct. In other words, the struct definition is like a general template for the type, and instances fill in that template with particular data to create values of the type. For example, we can declare a particular user as shown in Listing 5-2. Listing 5-2: Creating an instance of the User struct To get a specific value from a struct, we use dot notation. For example, to access this user’s email address, we use user1.email. If the instance is mutable, we can change a value by using the dot notation and assigning into a particular field. Listing 5-3 shows how to change the value in the email field of a mutable User instance. Listing 5-3: Changing the value in the email field of a User instance Note that the entire instance must be mutable; Rust doesn’t allow us to mark only certain fields as mutable. As with any expression, we can construct a new instance of the struct as the last expression in the function body to implicitly return that new instance. Listing 5-4 shows a build_user function that returns a User instance with the given email and username. The active field gets the value of true, and the sign_in_count gets a value of 1. Filename: src/main.rs # struct User {\n# active: bool,\n# username: String,\n# email: String,\n# sign_in_count: u64,\n# }\n# fn build_user(email: String, username: String) -> User { User { active: true, username: username, email: email, sign_in_count: 1, }\n}\n# # fn main() {\n# let user1 = build_user(\n# String::from(\"someone@example.com\"),\n# String::from(\"someusername123\"),\n# );\n# } Listing 5-4: A build_user function that takes an email and username and returns a User instance It makes sense to name the function parameters with the same name as the struct fields, but having to repeat the email and username field names and variables is a bit tedious. If the struct had more fields, repeating each name would get even more annoying. Luckily, there’s a convenient shorthand!","breadcrumbs":"Using Structs to Structure Related Data » Defining and Instantiating Structs » Defining and Instantiating Structs","id":"107","title":"Defining and Instantiating Structs"},"108":{"body":"Because the parameter names and the struct field names are exactly the same in Listing 5-4, we can use the field init shorthand syntax to rewrite build_user so it behaves exactly the same but doesn’t have the repetition of username and email, as shown in Listing 5-5. Filename: src/main.rs # struct User {\n# active: bool,\n# username: String,\n# email: String,\n# sign_in_count: u64,\n# }\n# fn build_user(email: String, username: String) -> User { User { active: true, username, email, sign_in_count: 1, }\n}\n# # fn main() {\n# let user1 = build_user(\n# String::from(\"someone@example.com\"),\n# String::from(\"someusername123\"),\n# );\n# } Listing 5-5: A build_user function that uses field init shorthand because the username and email parameters have the same name as struct fields Here, we’re creating a new instance of the User struct, which has a field named email. We want to set the email field’s value to the value in the email parameter of the build_user function. Because the email field and the email parameter have the same name, we only need to write email rather than email: email.","breadcrumbs":"Using Structs to Structure Related Data » Defining and Instantiating Structs » Using the Field Init Shorthand","id":"108","title":"Using the Field Init Shorthand"},"109":{"body":"It’s often useful to create a new instance of a struct that includes most of the values from another instance, but changes some. You can do this using struct update syntax . First, in Listing 5-6 we show how to create a new User instance in user2 regularly, without the update syntax. We set a new value for email but otherwise use the same values from user1 that we created in Listing 5-2. Listing 5-6: Creating a new User instance using all but one of the values from user1 Using struct update syntax, we can achieve the same effect with less code, as shown in Listing 5-7. The syntax .. specifies that the remaining fields not explicitly set should have the same value as the fields in the given instance. Filename: src/main.rs # struct User {\n# active: bool,\n# username: String,\n# email: String,\n# sign_in_count: u64,\n# }\n# fn main() { // --snip--\n# # let user1 = User {\n# email: String::from(\"someone@example.com\"),\n# username: String::from(\"someusername123\"),\n# active: true,\n# sign_in_count: 1,\n# }; let user2 = User { email: String::from(\"another@example.com\"), ..user1 };\n} Listing 5-7: Using struct update syntax to set a new email value for a User instance but to use the rest of the values from user1 The code in Listing 5-7 also creates an instance in user2 that has a different value for email but has the same values for the username, active, and sign_in_count fields from user1. The ..user1 must come last to specify that any remaining fields should get their values from the corresponding fields in user1, but we can choose to specify values for as many fields as we want in any order, regardless of the order of the fields in the struct’s definition. Note that the struct update syntax uses = like an assignment; this is because it moves the data, just as we saw in the “What Is Ownership?” section. In this example, we can no longer use user1 after creating user2 because the String in the username field of user1 was moved into user2. If we had given user2 new String values for both email and username, and thus only used the active and sign_in_count values from user1, then user1 would still be valid after creating user2. The types of active and sign_in_count are types that implement the Copy trait, so the behavior we discussed in the “Copying vs. Moving Out of a Collection” section would apply.","breadcrumbs":"Using Structs to Structure Related Data » Defining and Instantiating Structs » Creating Instances from Other Instances with Struct Update Syntax","id":"109","title":"Creating Instances from Other Instances with Struct Update Syntax"},"11":{"body":"Hundreds of companies, large and small, use Rust in production for a variety of tasks, including command line tools, web services, DevOps tooling, embedded devices, audio and video analysis and transcoding, cryptocurrencies, bioinformatics, search engines, Internet of Things applications, machine learning, and even major parts of the Firefox web browser.","breadcrumbs":"Introduction » Companies","id":"11","title":"Companies"},"110":{"body":"Rust also supports structs that look similar to tuples, called tuple structs . Tuple structs have the added meaning the struct name provides but don’t have names associated with their fields; rather, they just have the types of the fields. Tuple structs are useful when you want to give the whole tuple a name and make the tuple a different type from other tuples, and when naming each field as in a regular struct would be verbose or redundant. To define a tuple struct, start with the struct keyword and the struct name followed by the types in the tuple. For example, here we define and use two tuple structs named Color and Point: Filename: src/main.rs Note that the black and origin values are different types because they’re instances of different tuple structs. Each struct you define is its own type, even though the fields within the struct might have the same types. For example, a function that takes a parameter of type Color cannot take a Point as an argument, even though both types are made up of three i32 values. Otherwise, tuple struct instances are similar to tuples in that you can destructure them into their individual pieces, and you can use a . followed by the index to access an individual value.","breadcrumbs":"Using Structs to Structure Related Data » Defining and Instantiating Structs » Using Tuple Structs Without Named Fields to Create Different Types","id":"110","title":"Using Tuple Structs Without Named Fields to Create Different Types"},"111":{"body":"You can also define structs that don’t have any fields! These are called unit-like structs because they behave similarly to (), the unit type that we mentioned in “The Tuple Type” section. Unit-like structs can be useful when you need to implement a trait on some type but don’t have any data that you want to store in the type itself. We’ll discuss traits in Chapter 10. Here’s an example of declaring and instantiating a unit struct named AlwaysEqual: To define AlwaysEqual, we use the struct keyword, the name we want, and then a semicolon. No need for curly brackets or parentheses! Then we can get an instance of AlwaysEqual in the subject variable in a similar way: using the name we defined, without any curly brackets or parentheses. Imagine that later we’ll implement behavior for this type such that every instance of AlwaysEqual is always equal to every instance of any other type, perhaps to have a known result for testing purposes. We wouldn’t need any data to implement that behavior! You’ll see in Chapter 10 how to define traits and implement them on any type, including unit-like structs.","breadcrumbs":"Using Structs to Structure Related Data » Defining and Instantiating Structs » Unit-Like Structs Without Any Fields","id":"111","title":"Unit-Like Structs Without Any Fields"},"112":{"body":"In the User struct definition in Listing 5-1, we used the owned String type rather than the &str string slice type. This is a deliberate choice because we want each instance of this struct to own all of its data and for that data to be valid for as long as the entire struct is valid. It’s also possible for structs to store references to data owned by something else, but to do so requires the use of lifetimes , a Rust feature that we’ll discuss in Chapter 10. Lifetimes ensure that the data referenced by a struct is valid for as long as the struct is. Let’s say you try to store a reference in a struct without specifying lifetimes, like the following; this won’t work: Filename: src/main.rs struct User { active: bool, username: &str, email: &str, sign_in_count: u64,\n} fn main() { let user1 = User { active: true, username: \"someusername123\", email: \"someone@example.com\", sign_in_count: 1, };\n} The compiler will complain that it needs lifetime specifiers: $ cargo run Compiling structs v0.1.0 (file:///projects/structs)\nerror[E0106]: missing lifetime specifier --> src/main.rs:3:15 |\n3 | username: &str, | ^ expected named lifetime parameter |\nhelp: consider introducing a named lifetime parameter |\n1 ~ struct User<'a> {\n2 | active: bool,\n3 ~ username: &'a str, | error[E0106]: missing lifetime specifier --> src/main.rs:4:12 |\n4 | email: &str, | ^ expected named lifetime parameter |\nhelp: consider introducing a named lifetime parameter |\n1 ~ struct User<'a> {\n2 | active: bool,\n3 | username: &str,\n4 ~ email: &'a str, | For more information about this error, try `rustc --explain E0106`.\nerror: could not compile `structs` (bin \"structs\") due to 2 previous errors In Chapter 10, we’ll discuss how to fix these errors so you can store references in structs, but for now, we’ll fix errors like these using owned types like String instead of references like &str.","breadcrumbs":"Using Structs to Structure Related Data » Defining and Instantiating Structs » Ownership of Struct Data","id":"112","title":"Ownership of Struct Data"},"113":{"body":"Similar to our discussion in “Different Tuple Fields” , Rust’s borrow checker will track ownership permissions at both the struct-level and field-level. For example, if we borrow a field x of a Point structure, then both p and p.x temporarily lose their permissions (but not p.y): As a result, if we try and use p while p.x is mutably borrowed like this: Then the compiler will reject our program with the following error: error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable --> test.rs:10:17 |\n9 | let x = &mut p.x; | -------- mutable borrow occurs here\n10 | print_point(&p); | ^^ immutable borrow occurs here\n11 | *x += 1; | ------- mutable borrow later used here More generally, if you encounter an ownership error that involves a struct, you should consider which fields of your structure are supposed to be borrowed with which permissions. But be aware of the borrow checker’s limitations, since Rust may sometimes assume more fields are borrowed than they actually are.","breadcrumbs":"Using Structs to Structure Related Data » Defining and Instantiating Structs » Borrowing Fields of a Struct","id":"113","title":"Borrowing Fields of a Struct"},"114":{"body":"To understand when we might want to use structs, let’s write a program that calculates the area of a rectangle. We’ll start by using single variables, and then refactor the program until we’re using structs instead. Let’s make a new binary project with Cargo called rectangles that will take the width and height of a rectangle specified in pixels and calculate the area of the rectangle. Listing 5-8 shows a short program with one way of doing exactly that in our project’s src/main.rs . Filename: src/main.rs fn main() { let width1 = 30; let height1 = 50; println!( \"The area of the rectangle is {} square pixels.\", area(width1, height1) );\n} fn area(width: u32, height: u32) -> u32 { width * height\n} Listing 5-8: Calculating the area of a rectangle specified by separate width and height variables Now, run this program using cargo run: $ cargo run Compiling rectangles v0.1.0 (file:///projects/rectangles) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.42s Running `target/debug/rectangles`\nThe area of the rectangle is 1500 square pixels. This code succeeds in figuring out the area of the rectangle by calling the area function with each dimension, but we can do more to make this code clear and readable. The issue with this code is evident in the signature of area: # fn main() {\n# let width1 = 30;\n# let height1 = 50;\n# # println!(\n# \"The area of the rectangle is {} square pixels.\",\n# area(width1, height1)\n# );\n# }\n# fn area(width: u32, height: u32) -> u32 {\n# width * height\n# } The area function is supposed to calculate the area of one rectangle, but the function we wrote has two parameters, and it’s not clear anywhere in our program that the parameters are related. It would be more readable and more manageable to group width and height together. We’ve already discussed one way we might do that in “The Tuple Type” section of Chapter 3: by using tuples.","breadcrumbs":"Using Structs to Structure Related Data » An Example Program Using Structs » An Example Program Using Structs","id":"114","title":"An Example Program Using Structs"},"115":{"body":"Listing 5-9 shows another version of our program that uses tuples. Filename: src/main.rs fn main() { let rect1 = (30, 50); println!( \"The area of the rectangle is {} square pixels.\", area(rect1) );\n} fn area(dimensions: (u32, u32)) -> u32 { dimensions.0 * dimensions.1\n} Listing 5-9: Specifying the width and height of the rectangle with a tuple In one way, this program is better. Tuples let us add a bit of structure, and we’re now passing just one argument. But in another way, this version is less clear: tuples don’t name their elements, so we have to index into the parts of the tuple, making our calculation less obvious. Mixing up the width and height wouldn’t matter for the area calculation, but if we want to draw the rectangle on the screen, it would matter! We would have to keep in mind that width is the tuple index 0 and height is the tuple index 1. This would be even harder for someone else to figure out and keep in mind if they were to use our code. Because we haven’t conveyed the meaning of our data in our code, it’s now easier to introduce errors.","breadcrumbs":"Using Structs to Structure Related Data » An Example Program Using Structs » Refactoring with Tuples","id":"115","title":"Refactoring with Tuples"},"116":{"body":"We use structs to add meaning by labeling the data. We can transform the tuple we’re using into a struct with a name for the whole as well as names for the parts, as shown in Listing 5-10. Filename: src/main.rs struct Rectangle { width: u32, height: u32,\n} fn main() { let rect1 = Rectangle { width: 30, height: 50, }; println!( \"The area of the rectangle is {} square pixels.\", area(&rect1) );\n} fn area(rectangle: &Rectangle) -> u32 { rectangle.width * rectangle.height\n} Listing 5-10: Defining a Rectangle struct Here we’ve defined a struct and named it Rectangle. Inside the curly brackets, we defined the fields as width and height, both of which have type u32. Then, in main, we created a particular instance of Rectangle that has a width of 30 and a height of 50. Our area function is now defined with one parameter, which we’ve named rectangle, whose type is an immutable borrow of a struct Rectangle instance. As mentioned in Chapter 4, we want to borrow the struct rather than take ownership of it. This way, main retains its ownership and can continue using rect1, which is the reason we use the & in the function signature and where we call the function. The area function accesses the width and height fields of the Rectangle instance (note that accessing fields of a borrowed struct instance does not move the field values, which is why you often see borrows of structs). Our function signature for area now says exactly what we mean: calculate the area of Rectangle, using its width and height fields. This conveys that the width and height are related to each other, and it gives descriptive names to the values rather than using the tuple index values of 0 and 1. This is a win for clarity.","breadcrumbs":"Using Structs to Structure Related Data » An Example Program Using Structs » Refactoring with Structs: Adding More Meaning","id":"116","title":"Refactoring with Structs: Adding More Meaning"},"117":{"body":"It’d be useful to be able to print an instance of Rectangle while we’re debugging our program and see the values for all its fields. Listing 5-11 tries using the println! macro as we have used in previous chapters. This won’t work, however. Filename: src/main.rs struct Rectangle { width: u32, height: u32,\n} fn main() { let rect1 = Rectangle { width: 30, height: 50, }; println!(\"rect1 is {}\", rect1);\n} Listing 5-11: Attempting to print a Rectangle instance When we compile this code, we get an error with this core message: error[E0277]: `Rectangle` doesn't implement `std::fmt::Display` The println! macro can do many kinds of formatting, and by default, the curly brackets tell println! to use formatting known as Display: output intended for direct end user consumption. The primitive types we’ve seen so far implement Display by default because there’s only one way you’d want to show a 1 or any other primitive type to a user. But with structs, the way println! should format the output is less clear because there are more display possibilities: Do you want commas or not? Do you want to print the curly brackets? Should all the fields be shown? Due to this ambiguity, Rust doesn’t try to guess what we want, and structs don’t have a provided implementation of Display to use with println! and the {} placeholder. If we continue reading the errors, we’ll find this helpful note: = help: the trait `std::fmt::Display` is not implemented for `Rectangle` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead Let’s try it! The println! macro call will now look like println!(\"rect1 is {rect1:?}\");. Putting the specifier :? inside the curly brackets tells println! we want to use an output format called Debug. The Debug trait enables us to print our struct in a way that is useful for developers so we can see its value while we’re debugging our code. Compile the code with this change. Drat! We still get an error: error[E0277]: `Rectangle` doesn't implement `Debug` But again, the compiler gives us a helpful note: = help: the trait `Debug` is not implemented for `Rectangle` = note: add `#[derive(Debug)]` to `Rectangle` or manually `impl Debug for Rectangle` Rust does include functionality to print out debugging information, but we have to explicitly opt in to make that functionality available for our struct. To do that, we add the outer attribute #[derive(Debug)] just before the struct definition, as shown in Listing 5-12. Filename: src/main.rs #[derive(Debug)]\nstruct Rectangle { width: u32, height: u32,\n} fn main() { let rect1 = Rectangle { width: 30, height: 50, }; println!(\"rect1 is {rect1:?}\");\n} Listing 5-12: Adding the attribute to derive the Debug trait and printing the Rectangle instance using debug formatting Now when we run the program, we won’t get any errors, and we’ll see the following output: $ cargo run Compiling rectangles v0.1.0 (file:///projects/rectangles) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.48s Running `target/debug/rectangles`\nrect1 is Rectangle { width: 30, height: 50 } Nice! It’s not the prettiest output, but it shows the values of all the fields for this instance, which would definitely help during debugging. When we have larger structs, it’s useful to have output that’s a bit easier to read; in those cases, we can use {:#?} instead of {:?} in the println! string. In this example, using the {:#?} style will output the following: $ cargo run Compiling rectangles v0.1.0 (file:///projects/rectangles) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.48s Running `target/debug/rectangles`\nrect1 is Rectangle { width: 30, height: 50,\n} Another way to print out a value using the Debug format is to use the dbg! macro , which takes ownership of an expression (as opposed to println!, which takes a reference), prints the file and line number of where that dbg! macro call occurs in your code along with the resultant value of that expression, and returns ownership of the value. Note: Calling the dbg! macro prints to the standard error console stream (stderr), as opposed to println!, which prints to the standard output console stream (stdout). We’ll talk more about stderr and stdout in the “Writing Error Messages to Standard Error Instead of Standard Output” section in Chapter 12 . Here’s an example where we’re interested in the value that gets assigned to the width field, as well as the value of the whole struct in rect1: #[derive(Debug)]\nstruct Rectangle { width: u32, height: u32,\n} fn main() { let scale = 2; let rect1 = Rectangle { width: dbg!(30 * scale), height: 50, }; dbg!(&rect1);\n} We can put dbg! around the expression 30 * scale and, because dbg! returns ownership of the expression’s value, the width field will get the same value as if we didn’t have the dbg! call there. We don’t want dbg! to take ownership of rect1, so we use a reference to rect1 in the next call. Here’s what the output of this example looks like: $ cargo run Compiling rectangles v0.1.0 (file:///projects/rectangles) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.61s Running `target/debug/rectangles`\n[src/main.rs:10:16] 30 * scale = 60\n[src/main.rs:14:5] &rect1 = Rectangle { width: 60, height: 50,\n} We can see the first bit of output came from src/main.rs line 10 where we’re debugging the expression 30 * scale, and its resultant value is 60 (the Debug formatting implemented for integers is to print only their value). The dbg! call on line 14 of src/main.rs outputs the value of &rect1, which is the Rectangle struct. This output uses the pretty Debug formatting of the Rectangle type. The dbg! macro can be really helpful when you’re trying to figure out what your code is doing! In addition to the Debug trait, Rust has provided a number of traits for us to use with the derive attribute that can add useful behavior to our custom types. Those traits and their behaviors are listed in Appendix C . We’ll cover how to implement these traits with custom behavior as well as how to create your own traits in Chapter 10. There are also many attributes other than derive; for more information, see the “Attributes” section of the Rust Reference . Our area function is very specific: it only computes the area of rectangles. It would be helpful to tie this behavior more closely to our Rectangle struct because it won’t work with any other type. Let’s look at how we can continue to refactor this code by turning the area function into an area method defined on our Rectangle type.","breadcrumbs":"Using Structs to Structure Related Data » An Example Program Using Structs » Adding Useful Functionality with Derived Traits","id":"117","title":"Adding Useful Functionality with Derived Traits"},"118":{"body":"Methods are similar to functions: we declare them with the fn keyword and a name, they can have parameters and a return value, and they contain some code that’s run when the method is called from somewhere else. Unlike functions, methods are defined within the context of a struct (or an enum or a trait object, which we cover in Chapter 6 and Chapter 17 , respectively), and their first parameter is always self, which represents the instance of the struct the method is being called on.","breadcrumbs":"Using Structs to Structure Related Data » Method Syntax » Method Syntax","id":"118","title":"Method Syntax"},"119":{"body":"Let’s change the area function that has a Rectangle instance as a parameter and instead make an area method defined on the Rectangle struct, as shown in Listing 5-13. Filename: src/main.rs #[derive(Debug)]\nstruct Rectangle { width: u32, height: u32,\n} impl Rectangle { fn area(&self) -> u32 { self.width * self.height }\n} fn main() { let rect1 = Rectangle { width: 30, height: 50, }; println!( \"The area of the rectangle is {} square pixels.\", rect1.area() );\n} Listing 5-13: Defining an area method on the Rectangle struct To define the function within the context of Rectangle, we start an impl (implementation) block for Rectangle. Everything within this impl block will be associated with the Rectangle type. Then we move the area function within the impl curly brackets and change the first (and in this case, only) parameter to be self in the signature and everywhere within the body. In main, where we called the area function and passed rect1 as an argument, we can instead use method syntax to call the area method on our Rectangle instance. The method syntax goes after an instance: we add a dot followed by the method name, parentheses, and any arguments. In the signature for area, we use &self instead of rectangle: &Rectangle. The &self is actually short for self: &Self. Within an impl block, the type Self is an alias for the type that the impl block is for. Methods must have a parameter named self of type Self for their first parameter, so Rust lets you abbreviate this with only the name self in the first parameter spot. Note that we still need to use the & in front of the self shorthand to indicate that this method borrows the Self instance, just as we did in rectangle: &Rectangle. Methods can take ownership of self, borrow self immutably, as we’ve done here, or borrow self mutably, just as they can any other parameter. We chose &self here for the same reason we used &Rectangle in the function version: we don’t want to take ownership, and we just want to read the data in the struct, not write to it. If we wanted to change the instance that we’ve called the method on as part of what the method does, we’d use &mut self as the first parameter. Having a method that takes ownership of the instance by using just self as the first parameter is rare; this technique is usually used when the method transforms self into something else and you want to prevent the caller from using the original instance after the transformation. The main reason for using methods instead of functions, in addition to providing method syntax and not having to repeat the type of self in every method’s signature, is for organization. We’ve put all the things we can do with an instance of a type in one impl block rather than making future users of our code search for capabilities of Rectangle in various places in the library we provide. Note that we can choose to give a method the same name as one of the struct’s fields. For example, we can define a method on Rectangle that is also named width: Filename: src/main.rs # #[derive(Debug)]\n# struct Rectangle {\n# width: u32,\n# height: u32,\n# }\n# impl Rectangle { fn width(&self) -> bool { self.width > 0 }\n} fn main() { let rect1 = Rectangle { width: 30, height: 50, }; if rect1.width() { println!(\"The rectangle has a nonzero width; it is {}\", rect1.width); }\n} Here, we’re choosing to make the width method return true if the value in the instance’s width field is greater than 0 and false if the value is 0: we can use a field within a method of the same name for any purpose. In main, when we follow rect1.width with parentheses, Rust knows we mean the method width. When we don’t use parentheses, Rust knows we mean the field width. Often, but not always, when we give a method the same name as a field we want it to only return the value in the field and do nothing else. Methods like this are called getters , and Rust does not implement them automatically for struct fields as some other languages do. Getters are useful because you can make the field private but the method public, and thus enable read-only access to that field as part of the type’s public API. We will discuss what public and private are and how to designate a field or method as public or private in Chapter 7 .","breadcrumbs":"Using Structs to Structure Related Data » Method Syntax » Defining Methods","id":"119","title":"Defining Methods"},"12":{"body":"Rust is for people who want to build the Rust programming language, community, developer tools, and libraries. We’d love to have you contribute to the Rust language.","breadcrumbs":"Introduction » Open Source Developers","id":"12","title":"Open Source Developers"},"120":{"body":"Let’s practice using methods by implementing a second method on the Rectangle struct. This time we want an instance of Rectangle to take another instance of Rectangle and return true if the second Rectangle can fit completely within self (the first Rectangle); otherwise, it should return false. That is, once we’ve defined the can_hold method, we want to be able to write the program shown in Listing 5-14. Filename: src/main.rs fn main() { let rect1 = Rectangle { width: 30, height: 50, }; let rect2 = Rectangle { width: 10, height: 40, }; let rect3 = Rectangle { width: 60, height: 45, }; println!(\"Can rect1 hold rect2? {}\", rect1.can_hold(&rect2)); println!(\"Can rect1 hold rect3? {}\", rect1.can_hold(&rect3));\n} Listing 5-14: Using the as-yet-unwritten can_hold method The expected output would look like the following because both dimensions of rect2 are smaller than the dimensions of rect1, but rect3 is wider than rect1: Can rect1 hold rect2? true\nCan rect1 hold rect3? false We know we want to define a method, so it will be within the impl Rectangle block. The method name will be can_hold, and it will take an immutable borrow of another Rectangle as a parameter. We can tell what the type of the parameter will be by looking at the code that calls the method: rect1.can_hold(&rect2) passes in &rect2, which is an immutable borrow to rect2, an instance of Rectangle. This makes sense because we only need to read rect2 (rather than write, which would mean we’d need a mutable borrow), and we want main to retain ownership of rect2 so we can use it again after calling the can_hold method. The return value of can_hold will be a Boolean, and the implementation will check whether the width and height of self are greater than the width and height of the other Rectangle, respectively. Let’s add the new can_hold method to the impl block from Listing 5-13, shown in Listing 5-15. Filename: src/main.rs # #[derive(Debug)]\n# struct Rectangle {\n# width: u32,\n# height: u32,\n# }\n# impl Rectangle { fn area(&self) -> u32 { self.width * self.height } fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height }\n}\n# # fn main() {\n# let rect1 = Rectangle {\n# width: 30,\n# height: 50,\n# };\n# let rect2 = Rectangle {\n# width: 10,\n# height: 40,\n# };\n# let rect3 = Rectangle {\n# width: 60,\n# height: 45,\n# };\n# # println!(\"Can rect1 hold rect2? {}\", rect1.can_hold(&rect2));\n# println!(\"Can rect1 hold rect3? {}\", rect1.can_hold(&rect3));\n# } Listing 5-15: Implementing the can_hold method on Rectangle that takes another Rectangle instance as a parameter When we run this code with the main function in Listing 5-14, we’ll get our desired output. Methods can take multiple parameters that we add to the signature after the self parameter, and those parameters work just like parameters in functions.","breadcrumbs":"Using Structs to Structure Related Data » Method Syntax » Methods with More Parameters","id":"120","title":"Methods with More Parameters"},"121":{"body":"All functions defined within an impl block are called associated functions because they’re associated with the type named after the impl. We can define associated functions as functions that don’t have self as their first parameter (and thus are not methods) because they don’t need an instance of the type to work with. We’ve already used one function like this: the String::from function that’s defined on the String type. Associated functions that aren’t methods are often used for constructors that will return a new instance of the struct. These are often called new, but new isn’t a special name and isn’t built into the language. For example, we could choose to provide an associated function named square that would have one dimension parameter and use that as both width and height, thus making it easier to create a square Rectangle rather than having to specify the same value twice: Filename: src/main.rs # #[derive(Debug)]\n# struct Rectangle {\n# width: u32,\n# height: u32,\n# }\n# impl Rectangle { fn square(size: u32) -> Self { Self { width: size, height: size, } }\n}\n# # fn main() {\n# let sq = Rectangle::square(3);\n# } The Self keywords in the return type and in the body of the function are aliases for the type that appears after the impl keyword, which in this case is Rectangle. To call this associated function, we use the :: syntax with the struct name; let sq = Rectangle::square(3); is an example. This function is namespaced by the struct: the :: syntax is used for both associated functions and namespaces created by modules. We’ll discuss modules in Chapter 7 .","breadcrumbs":"Using Structs to Structure Related Data » Method Syntax » Associated Functions","id":"121","title":"Associated Functions"},"122":{"body":"Each struct is allowed to have multiple impl blocks. For example, Listing 5-15 is equivalent to the code shown in Listing 5-16, which has each method in its own impl block. # #[derive(Debug)]\n# struct Rectangle {\n# width: u32,\n# height: u32,\n# }\n# impl Rectangle { fn area(&self) -> u32 { self.width * self.height }\n} impl Rectangle { fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height }\n}\n# # fn main() {\n# let rect1 = Rectangle {\n# width: 30,\n# height: 50,\n# };\n# let rect2 = Rectangle {\n# width: 10,\n# height: 40,\n# };\n# let rect3 = Rectangle {\n# width: 60,\n# height: 45,\n# };\n# # println!(\"Can rect1 hold rect2? {}\", rect1.can_hold(&rect2));\n# println!(\"Can rect1 hold rect3? {}\", rect1.can_hold(&rect3));\n# } Listing 5-16: Rewriting Listing 5-15 using multiple impl blocks There’s no reason to separate these methods into multiple impl blocks here, but this is valid syntax. We’ll see a case in which multiple impl blocks are useful in Chapter 10, where we discuss generic types and traits.","breadcrumbs":"Using Structs to Structure Related Data » Method Syntax » Multiple impl Blocks","id":"122","title":"Multiple impl Blocks"},"123":{"body":"Using the concepts we’ve discussed so far, we can now see how method calls are syntactic sugar for function calls. For example, let’s say we have a rectangle struct with an area method and a set_width method: # struct Rectangle {\n# width: u32,\n# height: u32,\n# }\n# impl Rectangle { fn area(&self) -> u32 { self.width * self.height } fn set_width(&mut self, width: u32) { self.width = width; }\n} And let’s say we have a rectangle r. Then the method calls r.area() and r.set_width(2) are equivalent to this: # struct Rectangle {\n# width: u32,\n# height: u32,\n# }\n# # impl Rectangle {\n# fn area(&self) -> u32 {\n# self.width * self.height\n# }\n# # fn set_width(&mut self, width: u32) {\n# self.width = width;\n# }\n# }\n# # fn main() { let mut r = Rectangle { width: 1, height: 2 }; let area1 = r.area(); let area2 = Rectangle::area(&r); assert_eq!(area1, area2); r.set_width(2); Rectangle::set_width(&mut r, 2);\n# } The method call r.area() becomes Rectangle::area(&r). The function name is the associated function Rectangle::area. The function argument is the &self parameter. Rust automatically inserts the borrowing operator &. Note: if you are familiar with C or C++, you are used to two different syntaxes for method calls: r.area() and r->area(). Rust does not have an equivalent to the arrow operator ->. Rust will automatically reference and dereference the method receiver when you use the dot operator. The method call r.set_width(2) similarly becomes Rectangle::set_width(&mut r, 2). This method expects &mut self, so the first argument is a mutable borrow &mut r. The second argument is exactly the same, the number 2. As we described in Chapter 4.3 “Dereferencing a Pointer Accesses Its Data” , Rust will insert as many references and dereferences as needed to make the types match up for the self parameter. For example, here are two equivalent calls to area for a mutable reference to a boxed rectangle: # struct Rectangle {\n# width: u32,\n# height: u32,\n# }\n# # impl Rectangle {\n# fn area(&self) -> u32 {\n# self.width * self.height\n# }\n# # fn set_width(&mut self, width: u32) {\n# self.width = width;\n# }\n# }\n# fn main() { let r = &mut Box::new(Rectangle { width: 1, height: 2 }); let area1 = r.area(); let area2 = Rectangle::area(&**r); assert_eq!(area1, area2);\n# } Rust will add two dereferences (once for the mutable reference, once for the box) and then one immutable borrow because area expects &Rectangle. Note that this is also a situation where a mutable reference is “downgraded” into a shared reference, like we discussed in Chapter 4.2 . Conversely, you would not be allowed to call set_width on a value of type &Rectangle or &Box.","breadcrumbs":"Using Structs to Structure Related Data » Method Syntax » Method Calls are Syntactic Sugar for Function Calls","id":"123","title":"Method Calls are Syntactic Sugar for Function Calls"},"124":{"body":"Like we discussed in Chapter 4.2 “References and Borrowing” , methods must be called on structs that have the necessary permissions. As a running example, we will use these three methods that take &self, &mut self, and self, respectively. impl Rectangle { fn area(&self) -> u32 { self.width * self.height } fn set_width(&mut self, width: u32) { self.width = width; } fn max(self, other: Rectangle) -> Rectangle { Rectangle { width: self.width.max(other.width), height: self.height.max(other.height), } }\n} Reads and Writes with &self and &mut self If we make an owned rectangle with let rect = Rectangle { ... }, then rect has R and O permissions. With those permissions, it is permissible to call the area and max methods: However, if we try to call set_width, we are missing the W permission: Rust will reject this program with the corresponding error: error[E0596]: cannot borrow `rect` as mutable, as it is not declared as mutable --> test.rs:28:1 |\n24 | let rect = Rectangle { | ---- help: consider changing this to be mutable: `mut rect`\n...\n28 | rect.set_width(0); | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable We will get a similar error if we try to call set_width on an immutable reference to a Rectangle, even if the underlying rectangle is mutable: Moves with self Calling a method that expects self will move the input struct (unless the struct implements Copy). For example, we cannot use a Rectangle after passing it to max: Once we call rect.max(..), we move rect and so lose all permissions on it. Trying to compile this program would give us the following error: error[E0382]: borrow of moved value: `rect` --> test.rs:33:16 |\n24 | let rect = Rectangle { | ---- move occurs because `rect` has type `Rectangle`, which does not implement the `Copy` trait\n...\n32 | let max_rect = rect.max(other_rect); | --------------- `rect` moved due to this method call\n33 | println!(\"{}\", rect.area()); | ^^^^^^^^^^^ value borrowed here after move A similar situation arises if we try to call a self method on a reference. For instance, say we tried to make a method set_to_max that assigns self to the output of self.max(..): Then we can see that self is missing O permissions in the operation self.max(..). Rust therefore rejects this program with the following error: error[E0507]: cannot move out of `*self` which is behind a mutable reference --> test.rs:23:17 |\n23 | *self = self.max(other); | ^^^^^---------- | | | | | `*self` moved due to this method call | move occurs because `*self` has type `Rectangle`, which does not implement the `Copy` trait | This is the same kind of error we discussed in Chapter 4.3 “Copying vs. Moving Out of a Collection” . Good Moves and Bad Moves You might wonder: why does it matter if we move out of *self? In fact, for the case of Rectangle, it actually is safe to move out of *self, even though Rust doesn’t let you do it. For example, if we simulate a program that calls the rejected set_to_max, you can see how nothing unsafe occurs: The reason it’s safe to move out of *self is because Rectangle does not own any heap data. In fact, we can actually get Rust to compile set_to_max by simply adding #[derive(Copy, Clone)] to the definition of Rectangle: Notice that unlike before, self.max(other) no longer requires the O permission on *self or other. Remember that self.max(other) desugars to Rectangle::max(*self, other). The dereference *self does not require ownership over *self if Rectangle is copyable. You might wonder: why doesn’t Rust automatically derive Copy for Rectangle? Rust does not auto-derive Copy for stability across API changes. Imagine that the author of the Rectangle type decided to add a name: String field. Then all client code that relies on Rectangle being Copy would suddenly get rejected by the compiler. To avoid that issue, API authors must explicitly add #[derive(Copy)] to indicate that they expect their struct to always be Copy. To better understand the issue, let’s run a simulation. Say we added name: String to Rectangle. What would happen if Rust allowed set_to_max to compile? In this program, we call set_to_max with two rectangles r1 and r2. self is a mutable reference to r1 and other is a move of r2. After calling self.max(other), the max method consumes ownership of both rectangles. When max returns, Rust deallocates both strings “r1” and “r2” in the heap. Notice the problem: at the location L2, *self is supposed to be readable and writable. However, (*self).name (actually r1.name) has been deallocated. Therefore when we do *self = max, we encounter undefined behavior. When we overwrite *self, Rust will implicitly drop the data previously in *self. To make that behavior explicit, we have added drop(*self). After calling drop(*self), Rust attempts to free (*self).name a second time. That action is a double-free, which is undefined behavior. So remember: when you see an error like “cannot move out of *self”, that’s usually because you’re trying to call a self method on a reference like &self or &mut self. Rust is protecting you from a double-free.","breadcrumbs":"Using Structs to Structure Related Data » Method Syntax » Methods and Ownership","id":"124","title":"Methods and Ownership"},"125":{"body":"Structs let you create custom types that are meaningful for your domain. By using structs, you can keep associated pieces of data connected to each other and name each piece to make your code clear. In impl blocks, you can define functions that are associated with your type, and methods are a kind of associated function that let you specify the behavior that instances of your structs have. But structs aren’t the only way you can create custom types: let’s turn to Rust’s enum feature to add another tool to your toolbox.","breadcrumbs":"Using Structs to Structure Related Data » Method Syntax » Summary","id":"125","title":"Summary"},"126":{"body":"In this chapter, we’ll look at enumerations , also referred to as enums . Enums allow you to define a type by enumerating its possible variants . First we’ll define and use an enum to show how an enum can encode meaning along with data. Next, we’ll explore a particularly useful enum, called Option, which expresses that a value can be either something or nothing. Then we’ll look at how pattern matching in the match expression makes it easy to run different code for different values of an enum. Finally, we’ll cover how the if let construct is another convenient and concise idiom available to handle enums in your code.","breadcrumbs":"Enums and Pattern Matching » Enums and Pattern Matching","id":"126","title":"Enums and Pattern Matching"},"127":{"body":"Where structs give you a way of grouping together related fields and data, like a Rectangle with its width and height, enums give you a way of saying a value is one of a possible set of values. For example, we may want to say that Rectangle is one of a set of possible shapes that also includes Circle and Triangle. To do this, Rust allows us to encode these possibilities as an enum. Let’s look at a situation we might want to express in code and see why enums are useful and more appropriate than structs in this case. Say we need to work with IP addresses. Currently, two major standards are used for IP addresses: version four and version six. Because these are the only possibilities for an IP address that our program will come across, we can enumerate all possible variants, which is where enumeration gets its name. Any IP address can be either a version four or a version six address, but not both at the same time. That property of IP addresses makes the enum data structure appropriate because an enum value can only be one of its variants. Both version four and version six addresses are still fundamentally IP addresses, so they should be treated as the same type when the code is handling situations that apply to any kind of IP address. We can express this concept in code by defining an IpAddrKind enumeration and listing the possible kinds an IP address can be, V4 and V6. These are the variants of the enum: enum IpAddrKind { V4, V6,\n}\n# # fn main() {\n# let four = IpAddrKind::V4;\n# let six = IpAddrKind::V6;\n# # route(IpAddrKind::V4);\n# route(IpAddrKind::V6);\n# }\n# # fn route(ip_kind: IpAddrKind) {} IpAddrKind is now a custom data type that we can use elsewhere in our code.","breadcrumbs":"Enums and Pattern Matching » Defining an Enum » Defining an Enum","id":"127","title":"Defining an Enum"},"128":{"body":"We can create instances of each of the two variants of IpAddrKind like this: # enum IpAddrKind {\n# V4,\n# V6,\n# }\n# # fn main() { let four = IpAddrKind::V4; let six = IpAddrKind::V6;\n# # route(IpAddrKind::V4);\n# route(IpAddrKind::V6);\n# }\n# # fn route(ip_kind: IpAddrKind) {} Note that the variants of the enum are namespaced under its identifier, and we use a double colon to separate the two. This is useful because now both values IpAddrKind::V4 and IpAddrKind::V6 are of the same type: IpAddrKind. We can then, for instance, define a function that takes any IpAddrKind: # enum IpAddrKind {\n# V4,\n# V6,\n# }\n# # fn main() {\n# let four = IpAddrKind::V4;\n# let six = IpAddrKind::V6;\n# # route(IpAddrKind::V4);\n# route(IpAddrKind::V6);\n# }\n# fn route(ip_kind: IpAddrKind) {} And we can call this function with either variant: # enum IpAddrKind {\n# V4,\n# V6,\n# }\n# # fn main() {\n# let four = IpAddrKind::V4;\n# let six = IpAddrKind::V6;\n# route(IpAddrKind::V4); route(IpAddrKind::V6);\n# }\n# # fn route(ip_kind: IpAddrKind) {} Using enums has even more advantages. Thinking more about our IP address type, at the moment we don’t have a way to store the actual IP address data ; we only know what kind it is. Given that you just learned about structs in Chapter 5, you might be tempted to tackle this problem with structs as shown in Listing 6-1. Listing 6-1: Storing the data and IpAddrKind variant of an IP address using a struct Here, we’ve defined a struct IpAddr that has two fields: a kind field that is of type IpAddrKind (the enum we defined previously) and an address field of type String. We have two instances of this struct. The first is home, and it has the value IpAddrKind::V4 as its kind with associated address data of 127.0.0.1. The second instance is loopback. It has the other variant of IpAddrKind as its kind value, V6, and has address ::1 associated with it. We’ve used a struct to bundle the kind and address values together, so now the variant is associated with the value. However, representing the same concept using just an enum is more concise: rather than an enum inside a struct, we can put data directly into each enum variant. This new definition of the IpAddr enum says that both V4 and V6 variants will have associated String values: We attach data to each variant of the enum directly, so there is no need for an extra struct. Here, it’s also easier to see another detail of how enums work: the name of each enum variant that we define also becomes a function that constructs an instance of the enum. That is, IpAddr::V4() is a function call that takes a String argument and returns an instance of the IpAddr type. We automatically get this constructor function defined as a result of defining the enum. There’s another advantage to using an enum rather than a struct: each variant can have different types and amounts of associated data. Version four IP addresses will always have four numeric components that will have values between 0 and 255. If we wanted to store V4 addresses as four u8 values but still express V6 addresses as one String value, we wouldn’t be able to with a struct. Enums handle this case with ease: We’ve shown several different ways to define data structures to store version four and version six IP addresses. However, as it turns out, wanting to store IP addresses and encode which kind they are is so common that the standard library has a definition we can use! Let’s look at how the standard library defines IpAddr: it has the exact enum and variants that we’ve defined and used, but it embeds the address data inside the variants in the form of two different structs, which are defined differently for each variant: struct Ipv4Addr { // --snip--\n} struct Ipv6Addr { // --snip--\n} enum IpAddr { V4(Ipv4Addr), V6(Ipv6Addr),\n} This code illustrates that you can put any kind of data inside an enum variant: strings, numeric types, or structs, for example. You can even include another enum! Also, standard library types are often not much more complicated than what you might come up with. Note that even though the standard library contains a definition for IpAddr, we can still create and use our own definition without conflict because we haven’t brought the standard library’s definition into our scope. We’ll talk more about bringing types into scope in Chapter 7. Let’s look at another example of an enum in Listing 6-2: this one has a wide variety of types embedded in its variants. enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32),\n}\n# # fn main() {} Listing 6-2: A Message enum whose variants each store different amounts and types of values This enum has four variants with different types: Quit has no data associated with it at all. Move has named fields, like a struct does. Write includes a single String. ChangeColor includes three i32 values. Defining an enum with variants such as the ones in Listing 6-2 is similar to defining different kinds of struct definitions, except the enum doesn’t use the struct keyword and all the variants are grouped together under the Message type. The following structs could hold the same data that the preceding enum variants hold: struct QuitMessage; // unit struct\nstruct MoveMessage { x: i32, y: i32,\n}\nstruct WriteMessage(String); // tuple struct\nstruct ChangeColorMessage(i32, i32, i32); // tuple struct\n# # fn main() {} But if we used the different structs, each of which has its own type, we couldn’t as easily define a function to take any of these kinds of messages as we could with the Message enum defined in Listing 6-2, which is a single type. There is one more similarity between enums and structs: just as we’re able to define methods on structs using impl, we’re also able to define methods on enums. Here’s a method named call that we could define on our Message enum: # fn main() {\n# enum Message {\n# Quit,\n# Move { x: i32, y: i32 },\n# Write(String),\n# ChangeColor(i32, i32, i32),\n# }\n# impl Message { fn call(&self) { // method body would be defined here } } let m = Message::Write(String::from(\"hello\")); m.call();\n# } The body of the method would use self to get the value that we called the method on. In this example, we’ve created a variable m that has the value Message::Write(String::from(\"hello\")), and that is what self will be in the body of the call method when m.call() runs. Let’s look at another enum in the standard library that is very common and useful: Option.","breadcrumbs":"Enums and Pattern Matching » Defining an Enum » Enum Values","id":"128","title":"Enum Values"},"129":{"body":"This section explores a case study of Option, which is another enum defined by the standard library. The Option type encodes the very common scenario in which a value could be something or it could be nothing. For example, if you request the first item in a non-empty list, you would get a value. If you request the first item in an empty list, you would get nothing. Expressing this concept in terms of the type system means the compiler can check whether you’ve handled all the cases you should be handling; this functionality can prevent bugs that are extremely common in other programming languages. Programming language design is often thought of in terms of which features you include, but the features you exclude are important too. Rust doesn’t have the null feature that many other languages have. Null is a value that means there is no value there. In languages with null, variables can always be in one of two states: null or not-null. In his 2009 presentation “Null References: The Billion Dollar Mistake,” Tony Hoare, the inventor of null, has this to say: I call it my billion-dollar mistake. At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. The problem with null values is that if you try to use a null value as a not-null value, you’ll get an error of some kind. Because this null or not-null property is pervasive, it’s extremely easy to make this kind of error. However, the concept that null is trying to express is still a useful one: a null is a value that is currently invalid or absent for some reason. The problem isn’t really with the concept but with the particular implementation. As such, Rust does not have nulls, but it does have an enum that can encode the concept of a value being present or absent. This enum is Option, and it is defined by the standard library as follows: enum Option { None, Some(T),\n} The Option enum is so useful that it’s even included in the prelude; you don’t need to bring it into scope explicitly. Its variants are also included in the prelude: you can use Some and None directly without the Option:: prefix. The Option enum is still just a regular enum, and Some(T) and None are still variants of type Option. The syntax is a feature of Rust we haven’t talked about yet. It’s a generic type parameter, and we’ll cover generics in more detail in Chapter 10. For now, all you need to know is that means that the Some variant of the Option enum can hold one piece of data of any type, and that each concrete type that gets used in place of T makes the overall Option type a different type. Here are some examples of using Option values to hold number types and string types: The type of some_number is Option. The type of some_char is Option, which is a different type. Rust can infer these types because we’ve specified a value inside the Some variant. For absent_number, Rust requires us to annotate the overall Option type: the compiler can’t infer the type that the corresponding Some variant will hold by looking only at a None value. Here, we tell Rust that we mean for absent_number to be of type Option. When we have a Some value, we know that a value is present and the value is held within the Some. When we have a None value, in some sense it means the same thing as null: we don’t have a valid value. So why is having Option any better than having null? In short, because Option and T (where T can be any type) are different types, the compiler won’t let us use an Option value as if it were definitely a valid value. For example, this code won’t compile, because it’s trying to add an i8 to an Option: # fn main() { let x: i8 = 5; let y: Option = Some(5); let sum = x + y;\n# } If we run this code, we get an error message like this one: $ cargo run Compiling enums v0.1.0 (file:///projects/enums)\nerror[E0277]: cannot add `Option` to `i8` --> src/main.rs:5:17 |\n5 | let sum = x + y; | ^ no implementation for `i8 + Option` | = help: the trait `Add