@@ -15,28 +15,31 @@ the whole language, though not with the depth and precision of the
15
15
16
16
Rust is a systems programming language with a focus on type safety,
17
17
memory safety, concurrency and performance. It is intended for writing
18
- large, high performance applications while preventing several classes
18
+ large, high- performance applications while preventing several classes
19
19
of errors commonly found in languages like C++. Rust has a
20
- sophisticated memory model that enables many of the efficient data
21
- structures used in C++ while disallowing invalid memory access that
22
- would otherwise cause segmentation faults. Like other systems
23
- languages it is statically typed and compiled ahead of time.
20
+ sophisticated memory model that makes possible many of the efficient
21
+ data structures used in C++, while disallowing invalid memory accesses
22
+ that would otherwise cause segmentation faults. Like other systems
23
+ languages, it is statically typed and compiled ahead of time.
24
24
25
- As a multi-paradigm language it has strong support for writing code in
26
- procedural, functional and object-oriented styles. Some of it's nice
25
+ As a multi-paradigm language, Rust supports writing code in
26
+ procedural, functional and object-oriented styles. Some of its nice
27
27
high-level features include:
28
28
29
- * Pattern matching and algebraic data types (enums) - common in functional
30
- languages, pattern matching on ADTs provides a compact and expressive
31
- way to encode program logic
32
- * Task-based concurrency - Rust uses lightweight tasks that do not share
33
- memory
34
- * Higher-order functions - Closures in Rust are very powerful and used
35
- pervasively
36
- * Polymorphism - Rust's type system features a unique combination of
37
- Java-style interfaces and Haskell-style typeclasses
38
- * Generics - Functions and types can be parameterized over generic
39
- types with optional type constraints
29
+ * *** Pattern matching and algebraic data types (enums).*** Common in
30
+ functional languages, pattern matching on ADTs provides a compact
31
+ and expressive way to encode program logic.
32
+ * *** Task-based concurrency.*** Rust uses lightweight tasks that do
33
+ not share memory.
34
+ * *** Higher-order functions.*** Rust functions may take closures as
35
+ arguments or return closures as return values. Closures in Rust are
36
+ very powerful and used pervasively.
37
+ * *** Interface polymorphism.*** Rust's type system features a unique
38
+ combination of Java-style interfaces and Haskell-style typeclasses.
39
+ * *** Parametric polymorphism (generics).*** Functions and types can be
40
+ parameterized over type variables with optional type constraints.
41
+ * *** Type inference.*** Type annotations on local variable
42
+ declarations can be omitted.
40
43
41
44
## First impressions
42
45
@@ -229,7 +232,7 @@ into an error.
229
232
230
233
## Anatomy of a Rust program
231
234
232
- In its simplest form, a Rust program is simply a ` .rs ` file with some
235
+ In its simplest form, a Rust program is a ` .rs ` file with some
233
236
types and functions defined in it. If it has a ` main ` function, it can
234
237
be compiled to an executable. Rust does not allow code that's not a
235
238
declaration to appear at the top level of the file—all statements must
@@ -1181,61 +1184,59 @@ several of Rust's unique features as we encounter them.
1181
1184
1182
1185
Rust has three competing goals that inform its view of memory:
1183
1186
1184
- * Memory safety - memory that is managed by and is accessible to
1185
- the Rust language must be guaranteed to be valid. Under normal
1186
- circumstances it is impossible for Rust to trigger a segmentation
1187
- fault or leak memory
1188
- * Performance - high-performance low-level code tends to employ
1189
- a number of allocation strategies. low-performance high-level
1190
- code often uses a single, GC-based, heap allocation strategy
1191
- * Concurrency - Rust must maintain memory safety guarantees even
1192
- for code running in parallel
1187
+ * Memory safety: memory that is managed by and is accessible to the
1188
+ Rust language must be guaranteed to be valid; under normal
1189
+ circumstances it must be impossible for Rust to trigger a
1190
+ segmentation fault or leak memory
1191
+ * Performance: high-performance low-level code must be able to employ
1192
+ a number of allocation strategies; low-performance high-level code
1193
+ must be able to employ a single, garbage-collection-based, heap
1194
+ allocation strategy
1195
+ * Concurrency: Rust must maintain memory safety guarantees, even for
1196
+ code running in parallel
1193
1197
1194
1198
## How performance considerations influence the memory model
1195
1199
1196
- Many languages that ofter the kinds of memory safety guarentees that
1197
- Rust does have a single allocation strategy: objects live on the heap,
1198
- live for as long as they are needed, and are periodically garbage
1199
- collected. This is very straightforword both conceptually and in
1200
- implementation, but has very significant costs. Such languages tend to
1200
+ Most languages that offer strong memory safety guarantees rely upon a
1201
+ garbage-collected heap to manage all of the objects. This approach is
1202
+ straightforward both in concept and in implementation, but has
1203
+ significant costs. Languages that take this approach tend to
1201
1204
aggressively pursue ways to ameliorate allocation costs (think the
1202
- Java virtual machine ). Rust supports this strategy with _ shared
1203
- boxes_ , memory allocated on the heap that may be referred to (shared)
1205
+ Java Virtual Machine ). Rust supports this strategy with _ shared
1206
+ boxes_ : memory allocated on the heap that may be referred to (shared)
1204
1207
by multiple variables.
1205
1208
1206
- In comparison, languages like C++ offer a very precise control over
1207
- where objects are allocated. In particular, it is common to put
1208
- them directly on the stack, avoiding expensive heap allocation. In
1209
- Rust this is possible as well, and the compiler will use a clever
1210
- lifetime analysis to ensure that no variable can refer to stack
1209
+ By comparison, languages like C++ offer very precise control over
1210
+ where objects are allocated. In particular, it is common to put them
1211
+ directly on the stack, avoiding expensive heap allocation. In Rust
1212
+ this is possible as well, and the compiler will use a clever _ pointer
1213
+ lifetime analysis _ to ensure that no variable can refer to stack
1211
1214
objects after they are destroyed.
1212
1215
1213
1216
## How concurrency considerations influence the memory model
1214
1217
1215
- Memory safety in a concurrent environment tends to mean avoiding race
1218
+ Memory safety in a concurrent environment involves avoiding race
1216
1219
conditions between two threads of execution accessing the same
1217
- memory. Even high-level languages frequently avoid solving this
1218
- problem, requiring programmers to correctly employ locking to unsure
1219
- their program is free of races.
1220
-
1221
- Rust starts from the position that memory simply cannot be shared
1222
- between tasks. Experience in other languages has proven that isolating
1223
- each tasks' heap from each other is a reliable strategy and one that
1224
- is easy for programmers to reason about. Having isolated heaps
1225
- additionally means that garbage collection must only be done
1226
- per-heap. Rust never 'stops the world' to garbage collect memory.
1227
-
1228
- If Rust tasks have completely isolated heaps then that seems to imply
1229
- that any data transferred between them must be copied. While this
1230
- is a fine and useful way to implement communication between tasks,
1231
- it is also very inefficient for large data structures.
1232
-
1233
- Because of this Rust also introduces a global "exchange heap". Objects
1234
- allocated here have _ ownership semantics_ , meaning that there is only
1235
- a single variable that refers to them. For this reason they are
1236
- refered to as _ unique boxes_ . All tasks may allocate objects on this
1237
- heap, then transfer ownership of those allocations to other tasks,
1238
- avoiding expensive copies.
1220
+ memory. Even high-level languages often require programmers to
1221
+ correctly employ locking to ensure that a program is free of races.
1222
+
1223
+ Rust starts from the position that memory cannot be shared between
1224
+ tasks. Experience in other languages has proven that isolating each
1225
+ task's heap from the others is a reliable strategy and one that is
1226
+ easy for programmers to reason about. Heap isolation has the
1227
+ additional benefit that garbage collection must only be done
1228
+ per-heap. Rust never "stops the world" to garbage-collect memory.
1229
+
1230
+ Complete isolation of heaps between tasks implies that any data
1231
+ transferred between tasks must be copied. While this is a fine and
1232
+ useful way to implement communication between tasks, it is also very
1233
+ inefficient for large data structures. Because of this, Rust also
1234
+ employs a global _ exchange heap_ . Objects allocated in the exchange
1235
+ heap have _ ownership semantics_ , meaning that there is only a single
1236
+ variable that refers to them. For this reason, they are referred to as
1237
+ _ unique boxes_ . All tasks may allocate objects on the exchange heap,
1238
+ then transfer ownership of those objects to other tasks, avoiding
1239
+ expensive copies.
1239
1240
1240
1241
## What to be aware of
1241
1242
@@ -1249,11 +1250,11 @@ of each is key to using Rust effectively.
1249
1250
# Boxes and pointers
1250
1251
1251
1252
In contrast to a lot of modern languages, aggregate types like records
1252
- and enums are not represented as pointers to allocated memory. They
1253
- are, like in C and C++, represented directly. This means that if you
1254
- ` let x = {x: 1f, y: 1f}; ` , you are creating a record on the stack. If
1255
- you then copy it into a data structure, the whole record is copied,
1256
- not just a pointer.
1253
+ and enums are _ not _ represented as pointers to allocated memory in
1254
+ Rust. They are, as in C and C++, represented directly. This means that
1255
+ if you ` let x = {x: 1f, y: 1f}; ` , you are creating a record on the
1256
+ stack. If you then copy it into a data structure, the whole record is
1257
+ copied, not just a pointer.
1257
1258
1258
1259
For small records like ` point ` , this is usually more efficient than
1259
1260
allocating memory and going through a pointer. But for big records, or
@@ -1859,7 +1860,7 @@ like methods named 'new' and 'drop', but without 'fn', and without arguments
1859
1860
for drop.
1860
1861
1861
1862
In the constructor, the compiler will enforce that all fields are initialized
1862
- before doing anything which might allow them to be accessed. This includes
1863
+ before doing anything that might allow them to be accessed. This includes
1863
1864
returning from the constructor, calling any method on 'self', calling any
1864
1865
function with 'self' as an argument, or taking a reference to 'self'. Mutation
1865
1866
of immutable fields is possible only in the constructor, and only before doing
@@ -2504,6 +2505,31 @@ needed because it could also, for example, specify an implementation
2504
2505
of ` seq<int> ` —the ` of ` clause * refers* to a type, rather than defining
2505
2506
one.
2506
2507
2508
+ The type parameters bound by an iface are in scope in each of the
2509
+ method declarations. So, re-declaring the type parameter
2510
+ ` T ` as an explicit type parameter for ` len ` -- in either the iface or
2511
+ the impl -- would be a compile-time error.
2512
+
2513
+ ## The ` self ` type in interfaces
2514
+
2515
+ In an interface, ` self ` is a special type that you can think of as a
2516
+ type parameter. An implementation of the interface for any given type
2517
+ ` T ` replaces the ` self ` type parameter with ` T ` . The following
2518
+ interface describes types that support an equality operation:
2519
+
2520
+ ~~~~
2521
+ iface eq {
2522
+ fn equals(&&other: self) -> bool;
2523
+ }
2524
+
2525
+ impl of eq for int {
2526
+ fn equals(&&other: int) -> bool { other == self }
2527
+ }
2528
+ ~~~~
2529
+
2530
+ Notice that ` equals ` takes an ` int ` argument, rather than a ` self ` argument, in
2531
+ an implementation for type ` int ` .
2532
+
2507
2533
## Casting to an interface type
2508
2534
2509
2535
The above allows us to define functions that polymorphically act on
@@ -2934,9 +2960,9 @@ other. The function `task::spawn_listener()` supports this pattern. We'll look
2934
2960
briefly at how it is used.
2935
2961
2936
2962
To see how ` spawn_listener() ` works, we will create a child task
2937
- which receives ` uint ` messages, converts them to a string, and sends
2963
+ that receives ` uint ` messages, converts them to a string, and sends
2938
2964
the string in response. The child terminates when ` 0 ` is received.
2939
- Here is the function which implements the child task:
2965
+ Here is the function that implements the child task:
2940
2966
2941
2967
~~~~
2942
2968
# import comm::{port, chan, methods};
0 commit comments