Skip to content

Commit db058f8

Browse files
committed
TRPL: new introduction
1 parent e57410c commit db058f8

File tree

1 file changed

+208
-25
lines changed

1 file changed

+208
-25
lines changed

src/doc/trpl/README.md

Lines changed: 208 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,222 @@
11
% The Rust Programming Language
22

3-
Welcome! This book will teach you about [the Rust Programming
4-
Language](http://www.rust-lang.org/). Rust is a modern systems programming
5-
language focusing on safety and speed. It accomplishes these goals by being
6-
memory safe without using garbage collection.
3+
Welcome! This book will teach you about the [Rust Programming Language][rust].
4+
Rust is a systems programming language focused on three goals: safety, speed,
5+
and concurrency. It maintains these goals without having a garbage collector,
6+
making it a useful language for a number of use cases other languages aren’t
7+
good at: embedding in other languages, programs with specific space and time
8+
requirements, and writing low-level code, like device drivers and operating
9+
systems. It improves on current languages targeting this space by having a
10+
number of compile-time safety checks that produce no runtime overhead, while
11+
eliminating all data races. Rust also aims to achieve ‘zero-cost abstrations’
12+
even though some of these abstractions feel like those of a high-level
13+
language. Even then, Rust still allows precise control like a low-level
14+
language would.
715

8-
"The Rust Programming Language" is split into three sections, which you can
9-
navigate through the menu on the left.
16+
[rust]: http://rust-lang.org
1017

11-
<h2 class="section-header"><a href="basic.html">Basics</a></h2>
18+
“The Rust Programming Language” is split into seven sections. This introduction
19+
is the first. After this:
1220

13-
This section is a linear introduction to the basic syntax and semantics of
14-
Rust. It has individual sections on each part of Rust's syntax.
21+
* [Getting started][gs] - Set up your computer for Rust development.
22+
* [Learn Rust][lr] - Learn Rust programming through small projects.
23+
* [Effective Rust][er] - Higher-level concepts for writing excellent Rust code.
24+
* [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks.
25+
* [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet.
26+
* [Glossary][gl] - A reference of terms used in the book.
1527

16-
After reading "Basics," you will have a good foundation to learn more about
17-
Rust, and can write very simple programs.
28+
[gs]: getting-started.html
29+
[lr]: learn-rust.html
30+
[er]: effective-rust.html
31+
[ss]: syntax-and-semantics.html
32+
[nr]: nightly-rust.html
33+
[gl]: glossary.html
1834

19-
<h2 class="section-header"><a href="intermediate.html">Intermediate</a></h2>
35+
After reading this introduction, you’ll want to dive into either ‘Learn Rust’
36+
or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you
37+
want to dive in with a project, or ‘Syntax and Semantics’ if you prefer to
38+
start small, and learn a single concept thoroughly before moving onto the next.
39+
Copious cross-linking will help connect these parts together.
2040

21-
This section contains individual chapters, which are self-contained. They focus
22-
on specific topics, and can be read in any order.
41+
## A brief introduction to Rust
2342

24-
After reading "Intermediate," you will have a solid understanding of Rust,
25-
and will be able to understand most Rust code and write more complex programs.
43+
Is Rust a language you might be interested in? Let’s examine a few small code
44+
samples to show off a few of its strengths.
2645

27-
<h2 class="section-header"><a href="advanced.html">Advanced</a></h2>
46+
The main concept that makes Rust unique is called ‘ownership’. Consider this
47+
small example:
2848

29-
In a similar fashion to "Intermediate," this section is full of individual,
30-
deep-dive chapters, which stand alone and can be read in any order. These
31-
chapters focus on Rust's most complex features.
49+
```rust
50+
fn main() {
51+
let x = vec![1, 2, 3];
52+
}
53+
```
3254

33-
<h2 class="section-header"><a href="unstable.html">Unstable</a></h2>
55+
This program makes a [variable binding][var] named `x`. The value of this
56+
binding is a `Vec<T>`, a ‘vector’, that we create through a [macro][macro]
57+
defined in the standard library. This macro is called `vec`, and we invoke
58+
macros with a `!`. This follows a general principle of Rust: make things
59+
explicit. Macros can do significantly more complicated things than function
60+
calls, and so they’re visually distinct. The `!` also helps with parsing,
61+
making tooling easier to write, which is also important.
3462

35-
In a similar fashion to "Intermediate," this section is full of individual,
36-
deep-dive chapters, which stand alone and can be read in any order.
63+
It’s also worth noting that we didn’t need a type annotation here: while Rust
64+
is statically typed, we didn’t need to explicitly annotate the type. Rust has
65+
type inference to balance out the power of static typing with the verbosity of
66+
a simple implementation of it. If we wanted to annotate the type, we could:
3767

38-
This chapter contains things that are only available on the nightly channel of
39-
Rust.
68+
```rust
69+
fn main() {
70+
let x: Vec<i32> = vec![1, 2, 3];
71+
}
72+
```
73+
74+
Generally, these annotations are only added if there’s some kind of ambiguity
75+
to resolve.
76+
77+
Rust prefers stack allocation to heap allocation, and `x` is allocated on the
78+
stack. However, the `Vec<T>` type allocates space for the elements of the
79+
vector on the heap. If you’re not familiar with this distinction, you can
80+
ignore it for now, or check out [‘The Stack and the Heap’][heap]. As a systems
81+
programming language, Rust gives you the ability to control how your memory is
82+
allocated, but when we’re getting started, it’s less of a big deal.
83+
84+
[var]: variable-bindings.html
85+
[macro]: macros.html
86+
[heap]: the-stack-and-the-heap.html
87+
88+
Earlier, we mentioned that ‘ownership’ is the key new concept in Rust. In Rust
89+
parlance, `x` is said to ‘own’ the vector. This means that when `x` goes out of
90+
scope, the vector’s memory will be de-allocated. This is done deterministically
91+
by the Rust compiler, rather than through a mechanism such as a garbage
92+
collector. In other words, in Rust, you don’t call functions like `malloc` and
93+
`free` yourself: the compiler statically determines when you need to allocate
94+
or deallocate memory, and inserts those calls itself. To err is to be human,
95+
but compilers never forget.
96+
97+
Let’s add another line to our example:
98+
99+
```rust
100+
fn main() {
101+
let x = vec![1, 2, 3];
102+
103+
let y = &x[0];
104+
}
105+
```
106+
107+
We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to
108+
the first element of the vector. Rust’s references are similar to pointers in
109+
other languages, but with additional compile-time safety checks. References
110+
interact with the ownership system by [‘borrowing’][borrowing] what they point
111+
to, rather than owning it. The difference is, when the reference goes out of
112+
scope, it will not deallocate the underlying memory. If it did, we’d
113+
de-allocate twice, which is bad!
114+
115+
[borrowing]: references-and-borrowing.html
116+
117+
Let’s add a third line. It looks innocent enough, but causes a compiler error:
118+
119+
```rust,ignore
120+
fn main() {
121+
let x = vec![1, 2, 3];
122+
123+
let y = &x[0];
124+
125+
x.push(4);
126+
}
127+
```
128+
129+
`push` is a method on vectors that appends another element to the end of the
130+
vector. When we try to compile this program, we get an error:
131+
132+
```text
133+
error: cannot borrow immutable local variable `x` as mutable
134+
x.push(4);
135+
^
136+
```
137+
138+
Because `push` mutates the vector, it needs the vector to be mutable. But,
139+
bindings are immutable by default in Rust, and so we get a compile-time error
140+
telling us so. It’s easy to make the binding mutable: we add `mut` before
141+
the name of the binding. While that fixes our first error, it introduces
142+
another:
143+
144+
```rust,ignore
145+
fn main() {
146+
let mut x = vec![1, 2, 3];
147+
148+
let y = &x[0];
149+
150+
x.push(4);
151+
}
152+
```
153+
154+
Here’s the error:
155+
156+
```text
157+
error: cannot borrow `x` as mutable because it is also borrowed as immutable
158+
x.push(4);
159+
^
160+
note: previous borrow of `x` occurs here; the immutable borrow prevents
161+
subsequent moves or mutable borrows of `x` until the borrow ends
162+
let y = &x[0];
163+
^
164+
note: previous borrow ends here
165+
fn main() {
166+
167+
}
168+
^
169+
```
170+
171+
Whew! The Rust compiler gives quite detailed errors at times, and this is one
172+
of those times. As the error explains, while we made our binding mutable, we
173+
still cannot call `push`. This is because we already have a reference to an
174+
element of the vector, `y`. Mutating something while another reference exists
175+
is dangerous, because we may invalidate the reference. In this specific case,
176+
when we create the vector, we may have only allocated space for three elements.
177+
Adding a fourth would mean allocating a new chunk of memory for all those elements,
178+
copying the old values over, and updating the internal pointer to that memory.
179+
That all works just fine. The problem is that `y` wouldn’t get updated, and so
180+
we’d have a ‘dangling pointer’. That’s bad. Any use of `y` would be an error in
181+
this case, and so the compiler has caught this for us.
182+
183+
So how do we solve this problem? There are two approaches we can take. The first
184+
is making a copy rather than using a reference:
185+
186+
```rust
187+
fn main() {
188+
let mut x = vec![1, 2, 3];
189+
190+
let y = x[0].clone();
191+
192+
x.push(4);
193+
}
194+
```
195+
196+
Rust has [move semantics][move] by default, so if we want to make a copy of some
197+
data, we call the `clone()` method. In this example, `y` is no longer a reference
198+
to the vector stored in `x`, but a copy of its first element, `1`. Now that we
199+
don’t have a reference, our `push()` works just fine.
200+
201+
[move]: move-semantics.html
202+
203+
If we truly want a reference, we need the other option: ensure that our reference
204+
goes out of scope before we try to do the mutation. That looks like this:
205+
206+
```rust
207+
fn main() {
208+
let mut x = vec![1, 2, 3];
209+
210+
{
211+
let y = &x[0];
212+
}
213+
214+
x.push(4);
215+
}
216+
```
217+
218+
We created an inner scope with an additional set of curly braces. `y` will go out of
219+
scope before we call `push()`, and so we’re all good.
220+
221+
This concept of ownership isn’t just good for preventing danging pointers, but an
222+
entire set of related problems, like iterator invalidation, concurrency, and more.

0 commit comments

Comments
 (0)