Skip to content

Commit f70f8b4

Browse files
committed
Remove short intro from README
Originally, this was my 30 minute introduction, and we eventually made it the opener to the book. But as #25918 has shown, the example I use here has some issues. The good news is that Rust makes heap allocation syntatically expensive, but the bad news is that that means showing equivalent programs from Rust and other languages is difficult. After thinking about it, I'm not sure this section is pulling its weight, and since it has problems, I'd rather just pull it than try to re-write it right now. I think the book is fine without it. FIxes #25918
1 parent a216e84 commit f70f8b4

File tree

1 file changed

+3
-153
lines changed

1 file changed

+3
-153
lines changed

src/doc/trpl/README.md

+3-153
Original file line numberDiff line numberDiff line change
@@ -41,158 +41,8 @@ Copious cross-linking connects these parts together.
4141

4242
### Contributing
4343

44-
The source files from which this book is generated can be found on GitHub:
45-
[github.com/rust-lang/rust/tree/master/src/doc/trpl](https://github.com/rust-lang/rust/tree/master/src/doc/trpl)
44+
The source files from which this book is generated can be found on
45+
[GitHub][trpl].
4646

47-
## A brief introduction to Rust
47+
[trpl]: https://github.com/rust-lang/rust/tree/master/src/doc/trpl
4848

49-
Is Rust a language you might be interested in? Let’s examine a few small code
50-
samples to show off a few of its strengths.
51-
52-
The main concept that makes Rust unique is called ‘ownership’. Consider this
53-
small example:
54-
55-
```rust
56-
fn main() {
57-
let mut x = vec!["Hello", "world"];
58-
}
59-
```
60-
61-
This program makes a [variable binding][var] named `x`. The value of this
62-
binding is a `Vec<T>`, a ‘vector’, that we create through a [macro][macro]
63-
defined in the standard library. This macro is called `vec`, and we invoke
64-
macros with a `!`. This follows a general principle of Rust: make things
65-
explicit. Macros can do significantly more complicated things than function
66-
calls, and so they’re visually distinct. The `!` also helps with parsing,
67-
making tooling easier to write, which is also important.
68-
69-
We used `mut` to make `x` mutable: bindings are immutable by default in Rust.
70-
We’ll be mutating this vector later in the example.
71-
72-
It’s also worth noting that we didn’t need a type annotation here: while Rust
73-
is statically typed, we didn’t need to explicitly annotate the type. Rust has
74-
type inference to balance out the power of static typing with the verbosity of
75-
annotating types.
76-
77-
Rust prefers stack allocation to heap allocation: `x` is placed directly on the
78-
stack. However, the `Vec<T>` type allocates space for the elements of the vector
79-
on the heap. If you’re not familiar with this distinction, you can ignore it for
80-
now, or check out [‘The Stack and the Heap’][heap]. As a systems programming
81-
language, Rust gives us the ability to control how our memory is allocated, but
82-
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, we don’t call functions like `malloc` and
93-
`free` ourselves: the compiler statically determines when we need to allocate or
94-
deallocate memory, and inserts those calls itself. To err is to be human, but
95-
compilers never forget.
96-
97-
Let’s add another line to our example:
98-
99-
```rust
100-
fn main() {
101-
let mut x = vec!["Hello", "world"];
102-
103-
let y = &x[0];
104-
}
105-
```
106-
107-
We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to the
108-
first element of the vector. Rust’s references are similar to pointers in other
109-
languages, but with additional compile-time safety checks. References interact
110-
with the ownership system by [‘borrowing’][borrowing] what they point to, rather
111-
than owning it. The difference is, when the reference goes out of scope, it
112-
won't deallocate the underlying memory. If it did, we’d de-allocate twice, which
113-
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 mut x = vec!["Hello", "world"];
122-
123-
let y = &x[0];
124-
125-
x.push("foo");
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 `x` as mutable because it is also borrowed as immutable
134-
x.push("foo");
135-
^
136-
note: previous borrow of `x` occurs here; the immutable borrow prevents
137-
subsequent moves or mutable borrows of `x` until the borrow ends
138-
let y = &x[0];
139-
^
140-
note: previous borrow ends here
141-
fn main() {
142-
143-
}
144-
^
145-
```
146-
147-
Whew! The Rust compiler gives quite detailed errors at times, and this is one
148-
of those times. As the error explains, while we made our binding mutable, we
149-
still can't call `push`. This is because we already have a reference to an
150-
element of the vector, `y`. Mutating something while another reference exists
151-
is dangerous, because we may invalidate the reference. In this specific case,
152-
when we create the vector, we may have only allocated space for two elements.
153-
Adding a third would mean allocating a new chunk of memory for all those elements,
154-
copying the old values over, and updating the internal pointer to that memory.
155-
That all works just fine. The problem is that `y` wouldn’t get updated, and so
156-
we’d have a ‘dangling pointer’. That’s bad. Any use of `y` would be an error in
157-
this case, and so the compiler has caught this for us.
158-
159-
So how do we solve this problem? There are two approaches we can take. The first
160-
is making a copy rather than using a reference:
161-
162-
```rust
163-
fn main() {
164-
let mut x = vec!["Hello", "world"];
165-
166-
let y = x[0].clone();
167-
168-
x.push("foo");
169-
}
170-
```
171-
172-
Rust has [move semantics][move] by default, so if we want to make a copy of some
173-
data, we call the `clone()` method. In this example, `y` is no longer a reference
174-
to the vector stored in `x`, but a copy of its first element, `"Hello"`. Now
175-
that we don’t have a reference, our `push()` works just fine.
176-
177-
[move]: ownership.html#move-semantics
178-
179-
If we truly want a reference, we need the other option: ensure that our reference
180-
goes out of scope before we try to do the mutation. That looks like this:
181-
182-
```rust
183-
fn main() {
184-
let mut x = vec!["Hello", "world"];
185-
186-
{
187-
let y = &x[0];
188-
}
189-
190-
x.push("foo");
191-
}
192-
```
193-
194-
We created an inner scope with an additional set of curly braces. `y` will go out of
195-
scope before we call `push()`, and so we’re all good.
196-
197-
This concept of ownership isn’t just good for preventing dangling pointers, but an
198-
entire set of related problems, like iterator invalidation, concurrency, and more.

0 commit comments

Comments
 (0)