@@ -41,158 +41,8 @@ Copious cross-linking connects these parts together.
41
41
42
42
### Contributing
43
43
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 ] .
46
46
47
- ## A brief introduction to Rust
47
+ [ trpl ] : https://github.com/rust-lang/rust/tree/master/src/doc/trpl
48
48
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