Auto merge of #24195 - steveklabnik:rollup, r=steveklabnik
- Successful merges: #24143, #24149, #24167, #24178 - Failed merges:
This commit is contained in:
commit
30e7e6e8b0
@ -163,13 +163,17 @@ This is to make the language easier to parse for humans, especially in the face
|
||||
of higher-order functions. `fn foo<T>(f: fn(int): int, fn(T): U): U` is not
|
||||
particularly easy to read.
|
||||
|
||||
## `let` is used to introduce variables
|
||||
## Why is `let` used to introduce variables?
|
||||
|
||||
`let` not only defines variables, but can do pattern matching. One can also
|
||||
redeclare immutable variables with `let`. This is useful to avoid unnecessary
|
||||
`mut` annotations. An interesting historical note is that Rust comes,
|
||||
syntactically, most closely from ML, which also uses `let` to introduce
|
||||
bindings.
|
||||
We don't use the term "variable", instead, we use "variable bindings". The
|
||||
simplest way for binding is the `let` syntax, other ways including `if let`,
|
||||
`while let` and `match`. Bindings also exist in function arguments positions.
|
||||
|
||||
Bindings always happen in pattern matching positions, and it's also Rust's way
|
||||
to declare mutability. One can also redeclare mutability of a binding in
|
||||
pattern matching. This is useful to avoid unnecessary `mut` annotations. An
|
||||
interesting historical note is that Rust comes, syntactically, most closely
|
||||
from ML, which also uses `let` to introduce bindings.
|
||||
|
||||
See also [a long thread][alt] on renaming `let mut` to `var`.
|
||||
|
||||
|
@ -1,42 +1,64 @@
|
||||
# Summary
|
||||
|
||||
* [The Basics](basic.md)
|
||||
* [Getting Started](getting-started.md)
|
||||
* [Installing Rust](installing-rust.md)
|
||||
* [Hello, world!](hello-world.md)
|
||||
* [Hello, Cargo!](hello-cargo.md)
|
||||
* [Variable Bindings](variable-bindings.md)
|
||||
* [If](if.md)
|
||||
* [Functions](functions.md)
|
||||
* [Comments](comments.md)
|
||||
* [Compound Data Types](compound-data-types.md)
|
||||
* [Match](match.md)
|
||||
* [Looping](looping.md)
|
||||
* [Strings](strings.md)
|
||||
* [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md)
|
||||
* [Intermediate Rust](intermediate.md)
|
||||
* [Crates and Modules](crates-and-modules.md)
|
||||
* [Learn Rust](learn-rust.md)
|
||||
* [Effective Rust](effective-rust.md)
|
||||
* [The Stack and the Heap](the-stack-and-the-heap.md)
|
||||
* [`Debug` and `Display`](debug-and-display.md)
|
||||
* [Testing](testing.md)
|
||||
* [Pointers](pointers.md)
|
||||
* [Ownership](ownership.md)
|
||||
* [More Strings](more-strings.md)
|
||||
* [Patterns](patterns.md)
|
||||
* [Method Syntax](method-syntax.md)
|
||||
* [Associated Types](associated-types.md)
|
||||
* [Closures](closures.md)
|
||||
* [Documentation](documentation.md)
|
||||
* [Iterators](iterators.md)
|
||||
* [Generics](generics.md)
|
||||
* [Traits](traits.md)
|
||||
* [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md)
|
||||
* [Macros](macros.md)
|
||||
* [Concurrency](concurrency.md)
|
||||
* [Error Handling](error-handling.md)
|
||||
* [Documentation](documentation.md)
|
||||
* [Advanced Topics](advanced.md)
|
||||
* [FFI](ffi.md)
|
||||
* [Unsafe Code](unsafe.md)
|
||||
* [Advanced Macros](advanced-macros.md)
|
||||
* [Unstable Rust](unstable.md)
|
||||
* [Compiler Plugins](plugins.md)
|
||||
* [`Deref` coercions](deref-coercions.md)
|
||||
* [Syntax and Semantics](syntax-and-semantics.md)
|
||||
* [Variable Bindings](variable-bindings.md)
|
||||
* [Primitive Types](primitive-types.md)
|
||||
* [Functions](functions.md)
|
||||
* [Comments](comments.md)
|
||||
* [Structs](structs.md)
|
||||
* [Mutability](mutability.md)
|
||||
* [Method Syntax](method-syntax.md)
|
||||
* [Enums](enums.md)
|
||||
* [`if`](if.md)
|
||||
* [Match](match.md)
|
||||
* [Patterns](patterns.md)
|
||||
* [`for` loops](for-loops.md)
|
||||
* [`while` loops](while-loops.md)
|
||||
* [Ownership](ownership.md)
|
||||
* [References and Borrowing](references-and-borrowing.md)
|
||||
* [Lifetimes](lifetimes.md)
|
||||
* [Move semantics](move-semantics.md)
|
||||
* [Drop](drop.md)
|
||||
* [Vectors](vectors.md)
|
||||
* [Arrays](arrays.md)
|
||||
* [Slices](slices.md)
|
||||
* [Strings](strings.md)
|
||||
* [Traits](traits.md)
|
||||
* [Operators and Overloading](operators-and-overloading.md)
|
||||
* [Generics](generics.md)
|
||||
* [Trait Objects](trait-objects.md)
|
||||
* [Closures](closures.md)
|
||||
* [Universal Function Call Syntax](ufcs.md)
|
||||
* [Crates and Modules](crates-and-modules.md)
|
||||
* [`static`](static.md)
|
||||
* [`const`](const.md)
|
||||
* [Tuples](tuples.md)
|
||||
* [Tuple Structs](tuple-structs.md)
|
||||
* [Attributes](attributes.md)
|
||||
* [Conditional Compilation](conditional-compilation.md)
|
||||
* [`type` aliases](type-aliases.md)
|
||||
* [Casting between types](casting-between-types.md)
|
||||
* [Associated Types](associated-types.md)
|
||||
* [Unsized Types](unsized-types.md)
|
||||
* [Macros](macros.md)
|
||||
* [`unsafe` Code](unsafe-code.md)
|
||||
* [Nightly Rust](nightly-rust.md)
|
||||
* [Compiler Plugins](compiler-plugins.md)
|
||||
* [Inline Assembly](inline-assembly.md)
|
||||
* [No stdlib](no-stdlib.md)
|
||||
* [Intrinsics](intrinsics.md)
|
||||
@ -44,5 +66,4 @@
|
||||
* [Link args](link-args.md)
|
||||
* [Benchmark Tests](benchmark-tests.md)
|
||||
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
|
||||
* [Conclusion](conclusion.md)
|
||||
* [Glossary](glossary.md)
|
||||
|
@ -1,242 +0,0 @@
|
||||
% Advanced macros
|
||||
|
||||
This chapter picks up where the [introductory macro chapter](macros.html) left
|
||||
off.
|
||||
|
||||
# Syntactic requirements
|
||||
|
||||
Even when Rust code contains un-expanded macros, it can be parsed as a full
|
||||
[syntax tree][ast]. This property can be very useful for editors and other
|
||||
tools that process code. It also has a few consequences for the design of
|
||||
Rust's macro system.
|
||||
|
||||
[ast]: glossary.html#abstract-syntax-tree
|
||||
|
||||
One consequence is that Rust must determine, when it parses a macro invocation,
|
||||
whether the macro stands in for
|
||||
|
||||
* zero or more items,
|
||||
* zero or more methods,
|
||||
* an expression,
|
||||
* a statement, or
|
||||
* a pattern.
|
||||
|
||||
A macro invocation within a block could stand for some items, or for an
|
||||
expression / statement. Rust uses a simple rule to resolve this ambiguity. A
|
||||
macro invocation that stands for items must be either
|
||||
|
||||
* delimited by curly braces, e.g. `foo! { ... }`, or
|
||||
* terminated by a semicolon, e.g. `foo!(...);`
|
||||
|
||||
Another consequence of pre-expansion parsing is that the macro invocation must
|
||||
consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces
|
||||
must be balanced within a macro invocation. For example, `foo!([)` is
|
||||
forbidden. This allows Rust to know where the macro invocation ends.
|
||||
|
||||
More formally, the macro invocation body must be a sequence of *token trees*.
|
||||
A token tree is defined recursively as either
|
||||
|
||||
* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or
|
||||
* any other single token.
|
||||
|
||||
Within a matcher, each metavariable has a *fragment specifier*, identifying
|
||||
which syntactic form it matches.
|
||||
|
||||
* `ident`: an identifier. Examples: `x`; `foo`.
|
||||
* `path`: a qualified name. Example: `T::SpecialA`.
|
||||
* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`.
|
||||
* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`.
|
||||
* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`.
|
||||
* `stmt`: a single statement. Example: `let x = 3`.
|
||||
* `block`: a brace-delimited sequence of statements. Example:
|
||||
`{ log(error, "hi"); return 12; }`.
|
||||
* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`.
|
||||
* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`.
|
||||
* `tt`: a single token tree.
|
||||
|
||||
There are additional rules regarding the next token after a metavariable:
|
||||
|
||||
* `expr` variables must be followed by one of: `=> , ;`
|
||||
* `ty` and `path` variables must be followed by one of: `=> , : = > as`
|
||||
* `pat` variables must be followed by one of: `=> , =`
|
||||
* Other variables may be followed by any token.
|
||||
|
||||
These rules provide some flexibility for Rust's syntax to evolve without
|
||||
breaking existing macros.
|
||||
|
||||
The macro system does not deal with parse ambiguity at all. For example, the
|
||||
grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would
|
||||
be forced to choose between parsing `$t` and parsing `$e`. Changing the
|
||||
invocation syntax to put a distinctive token in front can solve the problem. In
|
||||
this case, you can write `$(T $t:ty)* E $e:exp`.
|
||||
|
||||
[item]: ../reference.html#items
|
||||
|
||||
# Scoping and macro import/export
|
||||
|
||||
Macros are expanded at an early stage in compilation, before name resolution.
|
||||
One downside is that scoping works differently for macros, compared to other
|
||||
constructs in the language.
|
||||
|
||||
Definition and expansion of macros both happen in a single depth-first,
|
||||
lexical-order traversal of a crate's source. So a macro defined at module scope
|
||||
is visible to any subsequent code in the same module, which includes the body
|
||||
of any subsequent child `mod` items.
|
||||
|
||||
A macro defined within the body of a single `fn`, or anywhere else not at
|
||||
module scope, is visible only within that item.
|
||||
|
||||
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||
parent module after the child's `mod` item. If the parent also has `macro_use`
|
||||
then the macros will be visible in the grandparent after the parent's `mod`
|
||||
item, and so forth.
|
||||
|
||||
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||
it controls which macros are loaded from the external crate, e.g.
|
||||
|
||||
```rust,ignore
|
||||
#[macro_use(foo, bar)]
|
||||
extern crate baz;
|
||||
```
|
||||
|
||||
If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
||||
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||
defined with the `#[macro_export]` attribute may be loaded.
|
||||
|
||||
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
||||
as well.
|
||||
|
||||
An example:
|
||||
|
||||
```rust
|
||||
macro_rules! m1 { () => (()) }
|
||||
|
||||
// visible here: m1
|
||||
|
||||
mod foo {
|
||||
// visible here: m1
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! m2 { () => (()) }
|
||||
|
||||
// visible here: m1, m2
|
||||
}
|
||||
|
||||
// visible here: m1
|
||||
|
||||
macro_rules! m3 { () => (()) }
|
||||
|
||||
// visible here: m1, m3
|
||||
|
||||
#[macro_use]
|
||||
mod bar {
|
||||
// visible here: m1, m3
|
||||
|
||||
macro_rules! m4 { () => (()) }
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
}
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
When this library is loaded with `#[macro_use] extern crate`, only `m2` will
|
||||
be imported.
|
||||
|
||||
The Rust Reference has a [listing of macro-related
|
||||
attributes](../reference.html#macro--and-plugin-related-attributes).
|
||||
|
||||
# The variable `$crate`
|
||||
|
||||
A further difficulty occurs when a macro is used in multiple crates. Say that
|
||||
`mylib` defines
|
||||
|
||||
```rust
|
||||
pub fn increment(x: u32) -> u32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_a {
|
||||
($x:expr) => ( ::increment($x) )
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_b {
|
||||
($x:expr) => ( ::mylib::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
`inc_a` only works within `mylib`, while `inc_b` only works outside the
|
||||
library. Furthermore, `inc_b` will break if the user imports `mylib` under
|
||||
another name.
|
||||
|
||||
Rust does not (yet) have a hygiene system for crate references, but it does
|
||||
provide a simple workaround for this problem. Within a macro imported from a
|
||||
crate named `foo`, the special macro variable `$crate` will expand to `::foo`.
|
||||
By contrast, when a macro is defined and then used in the same crate, `$crate`
|
||||
will expand to nothing. This means we can write
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
macro_rules! inc {
|
||||
($x:expr) => ( $crate::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
to define a single macro that works both inside and outside our library. The
|
||||
function name will expand to either `::increment` or `::mylib::increment`.
|
||||
|
||||
To keep this system simple and correct, `#[macro_use] extern crate ...` may
|
||||
only appear at the root of your crate, not inside `mod`. This ensures that
|
||||
`$crate` is a single identifier.
|
||||
|
||||
# The deep end
|
||||
|
||||
The introductory chapter mentioned recursive macros, but it did not give the
|
||||
full story. Recursive macros are useful for another reason: Each recursive
|
||||
invocation gives you another opportunity to pattern-match the macro's
|
||||
arguments.
|
||||
|
||||
As an extreme example, it is possible, though hardly advisable, to implement
|
||||
the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
|
||||
within Rust's macro system.
|
||||
|
||||
```rust
|
||||
macro_rules! bct {
|
||||
// cmd 0: d ... => ...
|
||||
(0, $($ps:tt),* ; $_d:tt)
|
||||
=> (bct!($($ps),*, 0 ; ));
|
||||
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 0 ; $($ds),*));
|
||||
|
||||
// cmd 1p: 1 ... => 1 ... p
|
||||
(1, $p:tt, $($ps:tt),* ; 1)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $p));
|
||||
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
|
||||
|
||||
// cmd 1p: 0 ... => 0 ...
|
||||
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
|
||||
// halt on empty data string
|
||||
( $($ps:tt),* ; )
|
||||
=> (());
|
||||
}
|
||||
```
|
||||
|
||||
Exercise: use macros to reduce duplication in the above definition of the
|
||||
`bct!` macro.
|
||||
|
||||
# Procedural macros
|
||||
|
||||
If Rust's macro system can't do what you need, you may want to write a
|
||||
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
|
||||
macros, this is significantly more work, the interfaces are much less stable,
|
||||
and bugs can be much harder to track down. In exchange you get the
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
||||
extension plugins are sometimes called *procedural macros* for this reason.
|
@ -1,8 +0,0 @@
|
||||
% Advanced
|
||||
|
||||
In a similar fashion to "Intermediate," this section is full of individual,
|
||||
deep-dive chapters, which stand alone and can be read in any order. These
|
||||
chapters focus on the most complex features, as well as some things that
|
||||
are only available in upcoming versions of Rust.
|
||||
|
||||
After reading "Advanced," you'll be a Rust expert!
|
@ -1,102 +0,0 @@
|
||||
% Arrays, Vectors, and Slices
|
||||
|
||||
Like many programming languages, Rust has list types to represent a sequence of
|
||||
things. The most basic is the *array*, a fixed-size list of elements of the
|
||||
same type. By default, arrays are immutable.
|
||||
|
||||
```{rust}
|
||||
let a = [1, 2, 3]; // a: [i32; 3]
|
||||
let mut m = [1, 2, 3]; // mut m: [i32; 3]
|
||||
```
|
||||
|
||||
There's a shorthand for initializing each element of an array to the same
|
||||
value. In this example, each element of `a` will be initialized to `0`:
|
||||
|
||||
```{rust}
|
||||
let a = [0; 20]; // a: [i32; 20]
|
||||
```
|
||||
|
||||
Arrays have type `[T; N]`. We'll talk about this `T` notation later, when we
|
||||
cover generics.
|
||||
|
||||
You can get the number of elements in an array `a` with `a.len()`, and use
|
||||
`a.iter()` to iterate over them with a for loop. This code will print each
|
||||
number in order:
|
||||
|
||||
```{rust}
|
||||
let a = [1, 2, 3];
|
||||
|
||||
println!("a has {} elements", a.len());
|
||||
for e in a.iter() {
|
||||
println!("{}", e);
|
||||
}
|
||||
```
|
||||
|
||||
You can access a particular element of an array with *subscript notation*:
|
||||
|
||||
```{rust}
|
||||
let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3]
|
||||
|
||||
println!("The second name is: {}", names[1]);
|
||||
```
|
||||
|
||||
Subscripts start at zero, like in most programming languages, so the first name
|
||||
is `names[0]` and the second name is `names[1]`. The above example prints
|
||||
`The second name is: Brian`. If you try to use a subscript that is not in the
|
||||
array, you will get an error: array access is bounds-checked at run-time. Such
|
||||
errant access is the source of many bugs in other systems programming
|
||||
languages.
|
||||
|
||||
A *vector* is a dynamic or "growable" array, implemented as the standard
|
||||
library type [`Vec<T>`](../std/vec/) (we'll talk about what the `<T>` means
|
||||
later). Vectors always allocate their data on the heap. Vectors are to slices
|
||||
what `String` is to `&str`. You can create them with the `vec!` macro:
|
||||
|
||||
```{rust}
|
||||
let v = vec![1, 2, 3]; // v: Vec<i32>
|
||||
```
|
||||
|
||||
(Notice that unlike the `println!` macro we've used in the past, we use square
|
||||
brackets `[]` with `vec!`. Rust allows you to use either in either situation,
|
||||
this is just convention.)
|
||||
|
||||
There's an alternate form of `vec!` for repeating an initial value:
|
||||
|
||||
```
|
||||
let v = vec![0; 10]; // ten zeroes
|
||||
```
|
||||
|
||||
You can get the length of, iterate over, and subscript vectors just like
|
||||
arrays. In addition, (mutable) vectors can grow automatically:
|
||||
|
||||
```{rust}
|
||||
let mut nums = vec![1, 2, 3]; // mut nums: Vec<i32>
|
||||
|
||||
nums.push(4);
|
||||
|
||||
println!("The length of nums is now {}", nums.len()); // Prints 4
|
||||
```
|
||||
|
||||
Vectors have many more useful methods.
|
||||
|
||||
A *slice* is a reference to (or "view" into) an array. They are useful for
|
||||
allowing safe, efficient access to a portion of an array without copying. For
|
||||
example, you might want to reference just one line of a file read into memory.
|
||||
By nature, a slice is not created directly, but from an existing variable.
|
||||
Slices have a length, can be mutable or not, and in many ways behave like
|
||||
arrays:
|
||||
|
||||
```{rust}
|
||||
let a = [0, 1, 2, 3, 4];
|
||||
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
|
||||
|
||||
for e in middle.iter() {
|
||||
println!("{}", e); // Prints 1, 2, 3
|
||||
}
|
||||
```
|
||||
|
||||
You can also take a slice of a vector, `String`, or `&str`, because they are
|
||||
backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover
|
||||
generics.
|
||||
|
||||
We have now learned all of the most basic Rust concepts.
|
48
src/doc/trpl/arrays.md
Normal file
48
src/doc/trpl/arrays.md
Normal file
@ -0,0 +1,48 @@
|
||||
% Arrays
|
||||
|
||||
Like many programming languages, Rust has list types to represent a sequence of
|
||||
things. The most basic is the *array*, a fixed-size list of elements of the
|
||||
same type. By default, arrays are immutable.
|
||||
|
||||
```{rust}
|
||||
let a = [1, 2, 3]; // a: [i32; 3]
|
||||
let mut m = [1, 2, 3]; // mut m: [i32; 3]
|
||||
```
|
||||
|
||||
There's a shorthand for initializing each element of an array to the same
|
||||
value. In this example, each element of `a` will be initialized to `0`:
|
||||
|
||||
```{rust}
|
||||
let a = [0; 20]; // a: [i32; 20]
|
||||
```
|
||||
|
||||
Arrays have type `[T; N]`. We'll talk about this `T` notation later, when we
|
||||
cover generics.
|
||||
|
||||
You can get the number of elements in an array `a` with `a.len()`, and use
|
||||
`a.iter()` to iterate over them with a for loop. This code will print each
|
||||
number in order:
|
||||
|
||||
```{rust}
|
||||
let a = [1, 2, 3];
|
||||
|
||||
println!("a has {} elements", a.len());
|
||||
for e in a.iter() {
|
||||
println!("{}", e);
|
||||
}
|
||||
```
|
||||
|
||||
You can access a particular element of an array with *subscript notation*:
|
||||
|
||||
```{rust}
|
||||
let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3]
|
||||
|
||||
println!("The second name is: {}", names[1]);
|
||||
```
|
||||
|
||||
Subscripts start at zero, like in most programming languages, so the first name
|
||||
is `names[0]` and the second name is `names[1]`. The above example prints
|
||||
`The second name is: Brian`. If you try to use a subscript that is not in the
|
||||
array, you will get an error: array access is bounds-checked at run-time. Such
|
||||
errant access is the source of many bugs in other systems programming
|
||||
languages.
|
3
src/doc/trpl/attributes.md
Normal file
3
src/doc/trpl/attributes.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Attributes
|
||||
|
||||
Coming Soon!
|
@ -1,7 +0,0 @@
|
||||
% Basics
|
||||
|
||||
This section is a linear introduction to the basic syntax and semantics of
|
||||
Rust. It has individual sections on each part of Rust's syntax.
|
||||
|
||||
After reading "Basics," you will have a good foundation to learn more about
|
||||
Rust, and can write very simple programs.
|
3
src/doc/trpl/casting-between-types.md
Normal file
3
src/doc/trpl/casting-between-types.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Casting Between Types
|
||||
|
||||
Coming Soon
|
@ -1,364 +0,0 @@
|
||||
% Compound Data Types
|
||||
|
||||
Rust, like many programming languages, has a number of different data types
|
||||
that are built-in. You've already done some simple work with integers and
|
||||
strings, but next, let's talk about some more complicated ways of storing data.
|
||||
|
||||
## Tuples
|
||||
|
||||
The first compound data type we're going to talk about is called the *tuple*.
|
||||
A tuple is an ordered list of fixed size. Like this:
|
||||
|
||||
```rust
|
||||
let x = (1, "hello");
|
||||
```
|
||||
|
||||
The parentheses and commas form this two-length tuple. Here's the same code, but
|
||||
with the type annotated:
|
||||
|
||||
```rust
|
||||
let x: (i32, &str) = (1, "hello");
|
||||
```
|
||||
|
||||
As you can see, the type of a tuple looks just like the tuple, but with each
|
||||
position having a type name rather than the value. Careful readers will also
|
||||
note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple.
|
||||
You have briefly seen `&str` used as a type before, and we'll discuss the
|
||||
details of strings later. In systems programming languages, strings are a bit
|
||||
more complex than in other languages. For now, just read `&str` as a *string
|
||||
slice*, and we'll learn more soon.
|
||||
|
||||
You can access the fields in a tuple through a *destructuring let*. Here's
|
||||
an example:
|
||||
|
||||
```rust
|
||||
let (x, y, z) = (1, 2, 3);
|
||||
|
||||
println!("x is {}", x);
|
||||
```
|
||||
|
||||
Remember before when I said the left-hand side of a `let` statement was more
|
||||
powerful than just assigning a binding? Here we are. We can put a pattern on
|
||||
the left-hand side of the `let`, and if it matches up to the right-hand side,
|
||||
we can assign multiple bindings at once. In this case, `let` "destructures,"
|
||||
or "breaks up," the tuple, and assigns the bits to three bindings.
|
||||
|
||||
This pattern is very powerful, and we'll see it repeated more later.
|
||||
|
||||
There are also a few things you can do with a tuple as a whole, without
|
||||
destructuring. You can assign one tuple into another, if they have the same
|
||||
contained types and [arity]. Tuples have the same arity when they have the same
|
||||
length.
|
||||
|
||||
```rust
|
||||
let mut x = (1, 2); // x: (i32, i32)
|
||||
let y = (2, 3); // y: (i32, i32)
|
||||
|
||||
x = y;
|
||||
```
|
||||
|
||||
You can also check for equality with `==`. Again, this will only compile if the
|
||||
tuples have the same type.
|
||||
|
||||
```rust
|
||||
let x = (1, 2, 3);
|
||||
let y = (2, 2, 4);
|
||||
|
||||
if x == y {
|
||||
println!("yes");
|
||||
} else {
|
||||
println!("no");
|
||||
}
|
||||
```
|
||||
|
||||
This will print `no`, because some of the values aren't equal.
|
||||
|
||||
Note that the order of the values is considered when checking for equality,
|
||||
so the following example will also print `no`.
|
||||
|
||||
```rust
|
||||
let x = (1, 2, 3);
|
||||
let y = (2, 1, 3);
|
||||
|
||||
if x == y {
|
||||
println!("yes");
|
||||
} else {
|
||||
println!("no");
|
||||
}
|
||||
```
|
||||
|
||||
One other use of tuples is to return multiple values from a function:
|
||||
|
||||
```rust
|
||||
fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }
|
||||
|
||||
fn main() {
|
||||
let (x, y) = next_two(5);
|
||||
println!("x, y = {}, {}", x, y);
|
||||
}
|
||||
```
|
||||
|
||||
Even though Rust functions can only return one value, a tuple *is* one value,
|
||||
that happens to be made up of more than one value. You can also see in this
|
||||
example how you can destructure a pattern returned by a function, as well.
|
||||
|
||||
Tuples are a very simple data structure, and so are not often what you want.
|
||||
Let's move on to their bigger sibling, structs.
|
||||
|
||||
## Structs
|
||||
|
||||
A struct is another form of a *record type*, just like a tuple. There's a
|
||||
difference: structs give each element that they contain a name, called a
|
||||
*field* or a *member*. Check it out:
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let origin = Point { x: 0, y: 0 }; // origin: Point
|
||||
|
||||
println!("The origin is at ({}, {})", origin.x, origin.y);
|
||||
}
|
||||
```
|
||||
|
||||
There's a lot going on here, so let's break it down. We declare a struct with
|
||||
the `struct` keyword, and then with a name. By convention, structs begin with a
|
||||
capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`.
|
||||
|
||||
We can create an instance of our struct via `let`, as usual, but we use a `key:
|
||||
value` style syntax to set each field. The order doesn't need to be the same as
|
||||
in the original declaration.
|
||||
|
||||
Finally, because fields have names, we can access the field through dot
|
||||
notation: `origin.x`.
|
||||
|
||||
The values in structs are immutable by default, like other bindings in Rust.
|
||||
Use `mut` to make them mutable:
|
||||
|
||||
```{rust}
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut point = Point { x: 0, y: 0 };
|
||||
|
||||
point.x = 5;
|
||||
|
||||
println!("The point is at ({}, {})", point.x, point.y);
|
||||
}
|
||||
```
|
||||
|
||||
This will print `The point is at (5, 0)`.
|
||||
|
||||
## Tuple Structs and Newtypes
|
||||
|
||||
Rust has another data type that's like a hybrid between a tuple and a struct,
|
||||
called a *tuple struct*. Tuple structs do have a name, but their fields don't:
|
||||
|
||||
|
||||
```{rust}
|
||||
struct Color(i32, i32, i32);
|
||||
struct Point(i32, i32, i32);
|
||||
```
|
||||
|
||||
These two will not be equal, even if they have the same values:
|
||||
|
||||
```{rust}
|
||||
# struct Color(i32, i32, i32);
|
||||
# struct Point(i32, i32, i32);
|
||||
let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
```
|
||||
|
||||
It is almost always better to use a struct than a tuple struct. We would write
|
||||
`Color` and `Point` like this instead:
|
||||
|
||||
```{rust}
|
||||
struct Color {
|
||||
red: i32,
|
||||
blue: i32,
|
||||
green: i32,
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
```
|
||||
|
||||
Now, we have actual names, rather than positions. Good names are important,
|
||||
and with a struct, we have actual names.
|
||||
|
||||
There _is_ one case when a tuple struct is very useful, though, and that's a
|
||||
tuple struct with only one element. We call this the *newtype* pattern, because
|
||||
it allows you to create a new type, distinct from that of its contained value
|
||||
and expressing its own semantic meaning:
|
||||
|
||||
```{rust}
|
||||
struct Inches(i32);
|
||||
|
||||
let length = Inches(10);
|
||||
|
||||
let Inches(integer_length) = length;
|
||||
println!("length is {} inches", integer_length);
|
||||
```
|
||||
|
||||
As you can see here, you can extract the inner integer type through a
|
||||
destructuring `let`, as we discussed previously in 'tuples.' In this case, the
|
||||
`let Inches(integer_length)` assigns `10` to `integer_length`.
|
||||
|
||||
## Enums
|
||||
|
||||
Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful
|
||||
feature of Rust, and are used throughout the standard library. An `enum` is
|
||||
a type which relates a set of alternates to a specific name. For example, below
|
||||
we define `Character` to be either a `Digit` or something else. These
|
||||
can be used via their fully scoped names: `Character::Other` (more about `::`
|
||||
below).
|
||||
|
||||
```rust
|
||||
enum Character {
|
||||
Digit(i32),
|
||||
Other,
|
||||
}
|
||||
```
|
||||
|
||||
Most normal types are allowed as the variant components of an `enum`. Here are
|
||||
some examples:
|
||||
|
||||
```rust
|
||||
struct Empty;
|
||||
struct Color(i32, i32, i32);
|
||||
struct Length(i32);
|
||||
struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
|
||||
struct HeightDatabase(Vec<i32>);
|
||||
```
|
||||
|
||||
You see that, depending on its type, an `enum` variant may or may not hold data.
|
||||
In `Character`, for instance, `Digit` gives a meaningful name for an `i32`
|
||||
value, where `Other` is only a name. However, the fact that they represent
|
||||
distinct categories of `Character` is a very useful property.
|
||||
|
||||
As with structures, the variants of an enum by default are not comparable with
|
||||
equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not
|
||||
support other binary operations such as `*` and `+`. As such, the following code
|
||||
is invalid for the example `Character` type:
|
||||
|
||||
```{rust,ignore}
|
||||
// These assignments both succeed
|
||||
let ten = Character::Digit(10);
|
||||
let four = Character::Digit(4);
|
||||
|
||||
// Error: `*` is not implemented for type `Character`
|
||||
let forty = ten * four;
|
||||
|
||||
// Error: `<=` is not implemented for type `Character`
|
||||
let four_is_smaller = four <= ten;
|
||||
|
||||
// Error: `==` is not implemented for type `Character`
|
||||
let four_equals_ten = four == ten;
|
||||
```
|
||||
|
||||
This may seem rather limiting, but it's a limitation which we can overcome.
|
||||
There are two ways: by implementing equality ourselves, or by pattern matching
|
||||
variants with [`match`][match] expressions, which you'll learn in the next
|
||||
chapter. We don't know enough about Rust to implement equality yet, but we can
|
||||
use the `Ordering` enum from the standard library, which does:
|
||||
|
||||
```
|
||||
enum Ordering {
|
||||
Less,
|
||||
Equal,
|
||||
Greater,
|
||||
}
|
||||
```
|
||||
|
||||
Because `Ordering` has already been defined for us, we will import it with the
|
||||
`use` keyword. Here's an example of how it is used:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y); // ordering: Ordering
|
||||
|
||||
if ordering == Ordering::Less {
|
||||
println!("less");
|
||||
} else if ordering == Ordering::Greater {
|
||||
println!("greater");
|
||||
} else if ordering == Ordering::Equal {
|
||||
println!("equal");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `::` symbol is used to indicate a namespace. In this case, `Ordering` lives
|
||||
in the `cmp` submodule of the `std` module. We'll talk more about modules later
|
||||
in the guide. For now, all you need to know is that you can `use` things from
|
||||
the standard library if you need them.
|
||||
|
||||
Okay, let's talk about the actual code in the example. `cmp` is a function that
|
||||
compares two things, and returns an `Ordering`. We return either
|
||||
`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on
|
||||
whether the first value is less than, greater than, or equal to the second. Note
|
||||
that each variant of the `enum` is namespaced under the `enum` itself: it's
|
||||
`Ordering::Greater`, not `Greater`.
|
||||
|
||||
The `ordering` variable has the type `Ordering`, and so contains one of the
|
||||
three values. We then do a bunch of `if`/`else` comparisons to check which
|
||||
one it is.
|
||||
|
||||
This `Ordering::Greater` notation is too long. Let's use another form of `use`
|
||||
to import the `enum` variants instead. This will avoid full scoping:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering::{self, Equal, Less, Greater};
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Less }
|
||||
else if a > b { Greater }
|
||||
else { Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y); // ordering: Ordering
|
||||
|
||||
if ordering == Less { println!("less"); }
|
||||
else if ordering == Greater { println!("greater"); }
|
||||
else if ordering == Equal { println!("equal"); }
|
||||
}
|
||||
```
|
||||
|
||||
Importing variants is convenient and compact, but can also cause name conflicts,
|
||||
so do this with caution. For this reason, it's normally considered better style
|
||||
to `use` an enum rather than its variants directly.
|
||||
|
||||
As you can see, `enum`s are quite a powerful tool for data representation, and
|
||||
are even more useful when they're [generic][generics] across types. Before we
|
||||
get to generics, though, let's talk about how to use enums with pattern
|
||||
matching, a tool that will let us deconstruct sum types (the type theory term
|
||||
for enums) like `Ordering` in a very elegant way that avoids all these messy
|
||||
and brittle `if`/`else`s.
|
||||
|
||||
|
||||
[arity]: ./glossary.html#arity
|
||||
[match]: ./match.html
|
||||
[generics]: ./generics.html
|
@ -1,11 +0,0 @@
|
||||
% Conclusion
|
||||
|
||||
We covered a lot of ground here. When you've mastered everything in this Guide,
|
||||
you will have a firm grasp of Rust development. There's a whole lot more
|
||||
out there, though, we've just covered the surface. There's tons of topics that
|
||||
you can dig deeper into, e.g. by reading the API documentation of the
|
||||
[standard library](http://doc.rust-lang.org/std/), by discovering solutions for
|
||||
common problems on [Rust by Example](http://rustbyexample.com/), or by browsing
|
||||
crates written by the community on [crates.io](https://crates.io/).
|
||||
|
||||
Happy hacking!
|
3
src/doc/trpl/conditional-compilation.md
Normal file
3
src/doc/trpl/conditional-compilation.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Conditional Compilation
|
||||
|
||||
Coming Soon!
|
3
src/doc/trpl/const.md
Normal file
3
src/doc/trpl/const.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `const`
|
||||
|
||||
Coming soon!
|
3
src/doc/trpl/debug-and-display.md
Normal file
3
src/doc/trpl/debug-and-display.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `Debug` and `Display`
|
||||
|
||||
Coming soon!
|
3
src/doc/trpl/deref-coercions.md
Normal file
3
src/doc/trpl/deref-coercions.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `Deref` coercions
|
||||
|
||||
Coming soon!
|
3
src/doc/trpl/drop.md
Normal file
3
src/doc/trpl/drop.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `Drop`
|
||||
|
||||
Coming soon!
|
1
src/doc/trpl/effective-rust.md
Normal file
1
src/doc/trpl/effective-rust.md
Normal file
@ -0,0 +1 @@
|
||||
% Effective Rust
|
149
src/doc/trpl/enums.md
Normal file
149
src/doc/trpl/enums.md
Normal file
@ -0,0 +1,149 @@
|
||||
% Enums
|
||||
|
||||
Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful
|
||||
feature of Rust, and are used throughout the standard library. An `enum` is
|
||||
a type which relates a set of alternates to a specific name. For example, below
|
||||
we define `Character` to be either a `Digit` or something else. These
|
||||
can be used via their fully scoped names: `Character::Other` (more about `::`
|
||||
below).
|
||||
|
||||
```rust
|
||||
enum Character {
|
||||
Digit(i32),
|
||||
Other,
|
||||
}
|
||||
```
|
||||
|
||||
Most normal types are allowed as the variant components of an `enum`. Here are
|
||||
some examples:
|
||||
|
||||
```rust
|
||||
struct Empty;
|
||||
struct Color(i32, i32, i32);
|
||||
struct Length(i32);
|
||||
struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
|
||||
struct HeightDatabase(Vec<i32>);
|
||||
```
|
||||
|
||||
You see that, depending on its type, an `enum` variant may or may not hold data.
|
||||
In `Character`, for instance, `Digit` gives a meaningful name for an `i32`
|
||||
value, where `Other` is only a name. However, the fact that they represent
|
||||
distinct categories of `Character` is a very useful property.
|
||||
|
||||
As with structures, the variants of an enum by default are not comparable with
|
||||
equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not
|
||||
support other binary operations such as `*` and `+`. As such, the following code
|
||||
is invalid for the example `Character` type:
|
||||
|
||||
```{rust,ignore}
|
||||
// These assignments both succeed
|
||||
let ten = Character::Digit(10);
|
||||
let four = Character::Digit(4);
|
||||
|
||||
// Error: `*` is not implemented for type `Character`
|
||||
let forty = ten * four;
|
||||
|
||||
// Error: `<=` is not implemented for type `Character`
|
||||
let four_is_smaller = four <= ten;
|
||||
|
||||
// Error: `==` is not implemented for type `Character`
|
||||
let four_equals_ten = four == ten;
|
||||
```
|
||||
|
||||
This may seem rather limiting, but it's a limitation which we can overcome.
|
||||
There are two ways: by implementing equality ourselves, or by pattern matching
|
||||
variants with [`match`][match] expressions, which you'll learn in the next
|
||||
chapter. We don't know enough about Rust to implement equality yet, but we can
|
||||
use the `Ordering` enum from the standard library, which does:
|
||||
|
||||
```
|
||||
enum Ordering {
|
||||
Less,
|
||||
Equal,
|
||||
Greater,
|
||||
}
|
||||
```
|
||||
|
||||
Because `Ordering` has already been defined for us, we will import it with the
|
||||
`use` keyword. Here's an example of how it is used:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y); // ordering: Ordering
|
||||
|
||||
if ordering == Ordering::Less {
|
||||
println!("less");
|
||||
} else if ordering == Ordering::Greater {
|
||||
println!("greater");
|
||||
} else if ordering == Ordering::Equal {
|
||||
println!("equal");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `::` symbol is used to indicate a namespace. In this case, `Ordering` lives
|
||||
in the `cmp` submodule of the `std` module. We'll talk more about modules later
|
||||
in the guide. For now, all you need to know is that you can `use` things from
|
||||
the standard library if you need them.
|
||||
|
||||
Okay, let's talk about the actual code in the example. `cmp` is a function that
|
||||
compares two things, and returns an `Ordering`. We return either
|
||||
`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on
|
||||
whether the first value is less than, greater than, or equal to the second. Note
|
||||
that each variant of the `enum` is namespaced under the `enum` itself: it's
|
||||
`Ordering::Greater`, not `Greater`.
|
||||
|
||||
The `ordering` variable has the type `Ordering`, and so contains one of the
|
||||
three values. We then do a bunch of `if`/`else` comparisons to check which
|
||||
one it is.
|
||||
|
||||
This `Ordering::Greater` notation is too long. Let's use another form of `use`
|
||||
to import the `enum` variants instead. This will avoid full scoping:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering::{self, Equal, Less, Greater};
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Less }
|
||||
else if a > b { Greater }
|
||||
else { Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y); // ordering: Ordering
|
||||
|
||||
if ordering == Less { println!("less"); }
|
||||
else if ordering == Greater { println!("greater"); }
|
||||
else if ordering == Equal { println!("equal"); }
|
||||
}
|
||||
```
|
||||
|
||||
Importing variants is convenient and compact, but can also cause name conflicts,
|
||||
so do this with caution. For this reason, it's normally considered better style
|
||||
to `use` an enum rather than its variants directly.
|
||||
|
||||
As you can see, `enum`s are quite a powerful tool for data representation, and
|
||||
are even more useful when they're [generic][generics] across types. Before we
|
||||
get to generics, though, let's talk about how to use enums with pattern
|
||||
matching, a tool that will let us deconstruct sum types (the type theory term
|
||||
for enums) like `Ordering` in a very elegant way that avoids all these messy
|
||||
and brittle `if`/`else`s.
|
||||
|
||||
|
||||
[arity]: ./glossary.html#arity
|
||||
[match]: ./match.html
|
||||
[generics]: ./generics.html
|
44
src/doc/trpl/for-loops.md
Normal file
44
src/doc/trpl/for-loops.md
Normal file
@ -0,0 +1,44 @@
|
||||
% `for` Loops
|
||||
|
||||
The `for` loop is used to loop a particular number of times. Rust's `for` loops
|
||||
work a bit differently than in other systems languages, however. Rust's `for`
|
||||
loop doesn't look like this "C-style" `for` loop:
|
||||
|
||||
```{c}
|
||||
for (x = 0; x < 10; x++) {
|
||||
printf( "%d\n", x );
|
||||
}
|
||||
```
|
||||
|
||||
Instead, it looks like this:
|
||||
|
||||
```{rust}
|
||||
for x in 0..10 {
|
||||
println!("{}", x); // x: i32
|
||||
}
|
||||
```
|
||||
|
||||
In slightly more abstract terms,
|
||||
|
||||
```{ignore}
|
||||
for var in expression {
|
||||
code
|
||||
}
|
||||
```
|
||||
|
||||
The expression is an iterator, which we will discuss in more depth later in the
|
||||
guide. The iterator gives back a series of elements. Each element is one
|
||||
iteration of the loop. That value is then bound to the name `var`, which is
|
||||
valid for the loop body. Once the body is over, the next value is fetched from
|
||||
the iterator, and we loop another time. When there are no more values, the
|
||||
`for` loop is over.
|
||||
|
||||
In our example, `0..10` is an expression that takes a start and an end position,
|
||||
and gives an iterator over those values. The upper bound is exclusive, though,
|
||||
so our loop will print `0` through `9`, not `10`.
|
||||
|
||||
Rust does not have the "C-style" `for` loop on purpose. Manually controlling
|
||||
each element of the loop is complicated and error prone, even for experienced C
|
||||
developers.
|
||||
|
||||
We'll talk more about `for` when we cover *iterators*, later in the Guide.
|
1
src/doc/trpl/getting-started.md
Normal file
1
src/doc/trpl/getting-started.md
Normal file
@ -0,0 +1 @@
|
||||
% Getting Started
|
@ -1,4 +1,4 @@
|
||||
% If
|
||||
% `if`
|
||||
|
||||
Rust's take on `if` is not particularly complex, but it's much more like the
|
||||
`if` you'll find in a dynamically typed language than in a more traditional
|
||||
@ -153,3 +153,5 @@ instead.
|
||||
|
||||
There's one more time in which you won't see a semicolon at the end of a line
|
||||
of Rust code. For that, we'll need our next concept: functions.
|
||||
|
||||
TODO: `if let`
|
||||
|
@ -1,7 +0,0 @@
|
||||
% Intermediate
|
||||
|
||||
This section contains individual chapters, which are self-contained. They focus
|
||||
on specific topics, and can be read in any order.
|
||||
|
||||
After reading "Intermediate," you will have a solid understanding of Rust,
|
||||
and will be able to understand most Rust code and write more complex programs.
|
1
src/doc/trpl/learn-rust.md
Normal file
1
src/doc/trpl/learn-rust.md
Normal file
@ -0,0 +1 @@
|
||||
% Learn Rust
|
3
src/doc/trpl/lifetimes.md
Normal file
3
src/doc/trpl/lifetimes.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Lifetimes
|
||||
|
||||
Coming soon!
|
@ -424,9 +424,240 @@ they are unstable and require feature gates.
|
||||
* `trace_macros!(true)` will enable a compiler message every time a macro is
|
||||
expanded. Use `trace_macros!(false)` later in expansion to turn it off.
|
||||
|
||||
# Further reading
|
||||
# Syntactic requirements
|
||||
|
||||
The [advanced macros chapter][] goes into more detail about macro syntax. It
|
||||
also describes how to share macros between different modules or crates.
|
||||
Even when Rust code contains un-expanded macros, it can be parsed as a full
|
||||
[syntax tree][ast]. This property can be very useful for editors and other
|
||||
tools that process code. It also has a few consequences for the design of
|
||||
Rust's macro system.
|
||||
|
||||
[advanced macros chapter]: advanced-macros.html
|
||||
[ast]: glossary.html#abstract-syntax-tree
|
||||
|
||||
One consequence is that Rust must determine, when it parses a macro invocation,
|
||||
whether the macro stands in for
|
||||
|
||||
* zero or more items,
|
||||
* zero or more methods,
|
||||
* an expression,
|
||||
* a statement, or
|
||||
* a pattern.
|
||||
|
||||
A macro invocation within a block could stand for some items, or for an
|
||||
expression / statement. Rust uses a simple rule to resolve this ambiguity. A
|
||||
macro invocation that stands for items must be either
|
||||
|
||||
* delimited by curly braces, e.g. `foo! { ... }`, or
|
||||
* terminated by a semicolon, e.g. `foo!(...);`
|
||||
|
||||
Another consequence of pre-expansion parsing is that the macro invocation must
|
||||
consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces
|
||||
must be balanced within a macro invocation. For example, `foo!([)` is
|
||||
forbidden. This allows Rust to know where the macro invocation ends.
|
||||
|
||||
More formally, the macro invocation body must be a sequence of *token trees*.
|
||||
A token tree is defined recursively as either
|
||||
|
||||
* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or
|
||||
* any other single token.
|
||||
|
||||
Within a matcher, each metavariable has a *fragment specifier*, identifying
|
||||
which syntactic form it matches.
|
||||
|
||||
* `ident`: an identifier. Examples: `x`; `foo`.
|
||||
* `path`: a qualified name. Example: `T::SpecialA`.
|
||||
* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`.
|
||||
* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`.
|
||||
* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`.
|
||||
* `stmt`: a single statement. Example: `let x = 3`.
|
||||
* `block`: a brace-delimited sequence of statements. Example:
|
||||
`{ log(error, "hi"); return 12; }`.
|
||||
* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`.
|
||||
* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`.
|
||||
* `tt`: a single token tree.
|
||||
|
||||
There are additional rules regarding the next token after a metavariable:
|
||||
|
||||
* `expr` variables must be followed by one of: `=> , ;`
|
||||
* `ty` and `path` variables must be followed by one of: `=> , : = > as`
|
||||
* `pat` variables must be followed by one of: `=> , =`
|
||||
* Other variables may be followed by any token.
|
||||
|
||||
These rules provide some flexibility for Rust's syntax to evolve without
|
||||
breaking existing macros.
|
||||
|
||||
The macro system does not deal with parse ambiguity at all. For example, the
|
||||
grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would
|
||||
be forced to choose between parsing `$t` and parsing `$e`. Changing the
|
||||
invocation syntax to put a distinctive token in front can solve the problem. In
|
||||
this case, you can write `$(T $t:ty)* E $e:exp`.
|
||||
|
||||
[item]: ../reference.html#items
|
||||
|
||||
# Scoping and macro import/export
|
||||
|
||||
Macros are expanded at an early stage in compilation, before name resolution.
|
||||
One downside is that scoping works differently for macros, compared to other
|
||||
constructs in the language.
|
||||
|
||||
Definition and expansion of macros both happen in a single depth-first,
|
||||
lexical-order traversal of a crate's source. So a macro defined at module scope
|
||||
is visible to any subsequent code in the same module, which includes the body
|
||||
of any subsequent child `mod` items.
|
||||
|
||||
A macro defined within the body of a single `fn`, or anywhere else not at
|
||||
module scope, is visible only within that item.
|
||||
|
||||
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||
parent module after the child's `mod` item. If the parent also has `macro_use`
|
||||
then the macros will be visible in the grandparent after the parent's `mod`
|
||||
item, and so forth.
|
||||
|
||||
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||
it controls which macros are loaded from the external crate, e.g.
|
||||
|
||||
```rust,ignore
|
||||
#[macro_use(foo, bar)]
|
||||
extern crate baz;
|
||||
```
|
||||
|
||||
If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
||||
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||
defined with the `#[macro_export]` attribute may be loaded.
|
||||
|
||||
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
||||
as well.
|
||||
|
||||
An example:
|
||||
|
||||
```rust
|
||||
macro_rules! m1 { () => (()) }
|
||||
|
||||
// visible here: m1
|
||||
|
||||
mod foo {
|
||||
// visible here: m1
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! m2 { () => (()) }
|
||||
|
||||
// visible here: m1, m2
|
||||
}
|
||||
|
||||
// visible here: m1
|
||||
|
||||
macro_rules! m3 { () => (()) }
|
||||
|
||||
// visible here: m1, m3
|
||||
|
||||
#[macro_use]
|
||||
mod bar {
|
||||
// visible here: m1, m3
|
||||
|
||||
macro_rules! m4 { () => (()) }
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
}
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
When this library is loaded with `#[macro_use] extern crate`, only `m2` will
|
||||
be imported.
|
||||
|
||||
The Rust Reference has a [listing of macro-related
|
||||
attributes](../reference.html#macro--and-plugin-related-attributes).
|
||||
|
||||
# The variable `$crate`
|
||||
|
||||
A further difficulty occurs when a macro is used in multiple crates. Say that
|
||||
`mylib` defines
|
||||
|
||||
```rust
|
||||
pub fn increment(x: u32) -> u32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_a {
|
||||
($x:expr) => ( ::increment($x) )
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_b {
|
||||
($x:expr) => ( ::mylib::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
`inc_a` only works within `mylib`, while `inc_b` only works outside the
|
||||
library. Furthermore, `inc_b` will break if the user imports `mylib` under
|
||||
another name.
|
||||
|
||||
Rust does not (yet) have a hygiene system for crate references, but it does
|
||||
provide a simple workaround for this problem. Within a macro imported from a
|
||||
crate named `foo`, the special macro variable `$crate` will expand to `::foo`.
|
||||
By contrast, when a macro is defined and then used in the same crate, `$crate`
|
||||
will expand to nothing. This means we can write
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
macro_rules! inc {
|
||||
($x:expr) => ( $crate::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
to define a single macro that works both inside and outside our library. The
|
||||
function name will expand to either `::increment` or `::mylib::increment`.
|
||||
|
||||
To keep this system simple and correct, `#[macro_use] extern crate ...` may
|
||||
only appear at the root of your crate, not inside `mod`. This ensures that
|
||||
`$crate` is a single identifier.
|
||||
|
||||
# The deep end
|
||||
|
||||
The introductory chapter mentioned recursive macros, but it did not give the
|
||||
full story. Recursive macros are useful for another reason: Each recursive
|
||||
invocation gives you another opportunity to pattern-match the macro's
|
||||
arguments.
|
||||
|
||||
As an extreme example, it is possible, though hardly advisable, to implement
|
||||
the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
|
||||
within Rust's macro system.
|
||||
|
||||
```rust
|
||||
macro_rules! bct {
|
||||
// cmd 0: d ... => ...
|
||||
(0, $($ps:tt),* ; $_d:tt)
|
||||
=> (bct!($($ps),*, 0 ; ));
|
||||
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 0 ; $($ds),*));
|
||||
|
||||
// cmd 1p: 1 ... => 1 ... p
|
||||
(1, $p:tt, $($ps:tt),* ; 1)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $p));
|
||||
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
|
||||
|
||||
// cmd 1p: 0 ... => 0 ...
|
||||
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
|
||||
// halt on empty data string
|
||||
( $($ps:tt),* ; )
|
||||
=> (());
|
||||
}
|
||||
```
|
||||
|
||||
Exercise: use macros to reduce duplication in the above definition of the
|
||||
`bct!` macro.
|
||||
|
||||
# Procedural macros
|
||||
|
||||
If Rust's macro system can't do what you need, you may want to write a
|
||||
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
|
||||
macros, this is significantly more work, the interfaces are much less stable,
|
||||
and bugs can be much harder to track down. In exchange you get the
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
||||
extension plugins are sometimes called *procedural macros* for this reason.
|
||||
|
@ -1,325 +0,0 @@
|
||||
% More Strings
|
||||
|
||||
Strings are an important concept to master in any programming language. If you
|
||||
come from a managed language background, you may be surprised at the complexity
|
||||
of string handling in a systems programming language. Efficient access and
|
||||
allocation of memory for a dynamically sized structure involves a lot of
|
||||
details. Luckily, Rust has lots of tools to help us here.
|
||||
|
||||
A **string** is a sequence of unicode scalar values encoded as a stream of
|
||||
UTF-8 bytes. All strings are guaranteed to be validly-encoded UTF-8 sequences.
|
||||
Additionally, strings are not null-terminated and can contain null bytes.
|
||||
|
||||
Rust has two main types of strings: `&str` and `String`.
|
||||
|
||||
# `&str`
|
||||
|
||||
The first kind is a `&str`. This is pronounced a 'string slice'.
|
||||
String literals are of the type `&str`:
|
||||
|
||||
```
|
||||
let string = "Hello there.";
|
||||
```
|
||||
|
||||
Like any Rust reference, string slices have an associated lifetime. A string
|
||||
literal is a `&'static str`. A string slice can be written without an explicit
|
||||
lifetime in many cases, such as in function arguments. In these cases the
|
||||
lifetime will be inferred:
|
||||
|
||||
```
|
||||
fn takes_slice(slice: &str) {
|
||||
println!("Got: {}", slice);
|
||||
}
|
||||
```
|
||||
|
||||
Like vector slices, string slices are simply a pointer plus a length. This
|
||||
means that they're a 'view' into an already-allocated string, such as a
|
||||
string literal or a `String`.
|
||||
|
||||
## `str`
|
||||
|
||||
You may occasionally see references to a `str` type, without the `&`. While
|
||||
this type does exist, it’s not something you want to use yourself. Sometimes,
|
||||
people confuse `str` for `String`, and write this:
|
||||
|
||||
```rust
|
||||
struct S {
|
||||
s: str,
|
||||
}
|
||||
```
|
||||
|
||||
This leads to ugly errors:
|
||||
|
||||
```text
|
||||
error: the trait `core::marker::Sized` is not implemented for the type `str` [E0277]
|
||||
note: `str` does not have a constant size known at compile-time
|
||||
```
|
||||
|
||||
Instead, this `struct` should be
|
||||
|
||||
```rust
|
||||
struct S {
|
||||
s: String,
|
||||
}
|
||||
```
|
||||
|
||||
So let’s talk about `String`s.
|
||||
|
||||
# `String`
|
||||
|
||||
A `String` is a heap-allocated string. This string is growable, and is
|
||||
also guaranteed to be UTF-8. `String`s are commonly created by
|
||||
converting from a string slice using the `to_string` method.
|
||||
|
||||
```
|
||||
let mut s = "Hello".to_string();
|
||||
println!("{}", s);
|
||||
|
||||
s.push_str(", world.");
|
||||
println!("{}", s);
|
||||
```
|
||||
|
||||
A reference to a `String` will automatically coerce to a string slice:
|
||||
|
||||
```
|
||||
fn takes_slice(slice: &str) {
|
||||
println!("Got: {}", slice);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Hello".to_string();
|
||||
takes_slice(&s);
|
||||
}
|
||||
```
|
||||
|
||||
You can also get a `&str` from a stack-allocated array of bytes:
|
||||
|
||||
```
|
||||
use std::str;
|
||||
|
||||
let x: &[u8] = &[b'a', b'b'];
|
||||
let stack_str: &str = str::from_utf8(x).unwrap();
|
||||
```
|
||||
|
||||
# Best Practices
|
||||
|
||||
## `String` vs. `&str`
|
||||
|
||||
In general, you should prefer `String` when you need ownership, and `&str` when
|
||||
you just need to borrow a string. This is very similar to using `Vec<T>` vs. `&[T]`,
|
||||
and `T` vs `&T` in general.
|
||||
|
||||
This means starting off with this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn foo(s: &str) {
|
||||
```
|
||||
|
||||
and only moving to this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn foo(s: String) {
|
||||
```
|
||||
|
||||
if you have good reason. It's not polite to hold on to ownership you don't
|
||||
need, and it can make your lifetimes more complex.
|
||||
|
||||
## Generic functions
|
||||
|
||||
To write a function that's generic over types of strings, use `&str`.
|
||||
|
||||
```
|
||||
fn some_string_length(x: &str) -> usize {
|
||||
x.len()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Hello, world";
|
||||
|
||||
println!("{}", some_string_length(s));
|
||||
|
||||
let s = "Hello, world".to_string();
|
||||
|
||||
println!("{}", some_string_length(&s));
|
||||
}
|
||||
```
|
||||
|
||||
Both of these lines will print `12`.
|
||||
|
||||
## Indexing strings
|
||||
|
||||
You may be tempted to try to access a certain character of a `String`, like
|
||||
this:
|
||||
|
||||
```{rust,ignore}
|
||||
let s = "hello".to_string();
|
||||
|
||||
println!("{}", s[0]);
|
||||
```
|
||||
|
||||
This does not compile. This is on purpose. In the world of UTF-8, direct
|
||||
indexing is basically never what you want to do. The reason is that each
|
||||
character can be a variable number of bytes. This means that you have to iterate
|
||||
through the characters anyway, which is an O(n) operation.
|
||||
|
||||
There's 3 basic levels of unicode (and its encodings):
|
||||
|
||||
- code units, the underlying data type used to store everything
|
||||
- code points/unicode scalar values (char)
|
||||
- graphemes (visible characters)
|
||||
|
||||
Rust provides iterators for each of these situations:
|
||||
|
||||
- `.bytes()` will iterate over the underlying bytes
|
||||
- `.chars()` will iterate over the code points
|
||||
- `.graphemes()` will iterate over each grapheme
|
||||
|
||||
Usually, the `graphemes()` method on `&str` is what you want:
|
||||
|
||||
```
|
||||
# #![feature(unicode)]
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.graphemes(true) {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```text
|
||||
u͔
|
||||
n͈̰̎
|
||||
i̙̮͚̦
|
||||
c͚̉
|
||||
o̼̩̰͗
|
||||
d͔̆̓ͥ
|
||||
é
|
||||
```
|
||||
|
||||
Note that `l` has the type `&str` here, since a single grapheme can consist of
|
||||
multiple codepoints, so a `char` wouldn't be appropriate.
|
||||
|
||||
This will print out each visible character in turn, as you'd expect: first `u͔`, then
|
||||
`n͈̰̎`, etc. If you wanted each individual codepoint of each grapheme, you can use `.chars()`:
|
||||
|
||||
```
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.chars() {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```text
|
||||
u
|
||||
͔
|
||||
n
|
||||
̎
|
||||
͈
|
||||
̰
|
||||
i
|
||||
̙
|
||||
̮
|
||||
͚
|
||||
̦
|
||||
c
|
||||
̉
|
||||
͚
|
||||
o
|
||||
͗
|
||||
̼
|
||||
̩
|
||||
̰
|
||||
d
|
||||
̆
|
||||
̓
|
||||
ͥ
|
||||
͔
|
||||
e
|
||||
́
|
||||
```
|
||||
|
||||
You can see how some of them are combining characters, and therefore the output
|
||||
looks a bit odd.
|
||||
|
||||
If you want the individual byte representation of each codepoint, you can use
|
||||
`.bytes()`:
|
||||
|
||||
```
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.bytes() {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This will print:
|
||||
|
||||
```text
|
||||
117
|
||||
205
|
||||
148
|
||||
110
|
||||
204
|
||||
142
|
||||
205
|
||||
136
|
||||
204
|
||||
176
|
||||
105
|
||||
204
|
||||
153
|
||||
204
|
||||
174
|
||||
205
|
||||
154
|
||||
204
|
||||
166
|
||||
99
|
||||
204
|
||||
137
|
||||
205
|
||||
154
|
||||
111
|
||||
205
|
||||
151
|
||||
204
|
||||
188
|
||||
204
|
||||
169
|
||||
204
|
||||
176
|
||||
100
|
||||
204
|
||||
134
|
||||
205
|
||||
131
|
||||
205
|
||||
165
|
||||
205
|
||||
148
|
||||
101
|
||||
204
|
||||
129
|
||||
```
|
||||
|
||||
Many more bytes than graphemes!
|
||||
|
||||
# `Deref` coercions
|
||||
|
||||
References to `String`s will automatically coerce into `&str`s. Like this:
|
||||
|
||||
```
|
||||
fn hello(s: &str) {
|
||||
println!("Hello, {}!", s);
|
||||
}
|
||||
|
||||
let slice = "Steve";
|
||||
let string = "Steve".to_string();
|
||||
|
||||
hello(slice);
|
||||
hello(&string);
|
||||
```
|
3
src/doc/trpl/move-semantics.md
Normal file
3
src/doc/trpl/move-semantics.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Move Semantics
|
||||
|
||||
Coming Soon
|
3
src/doc/trpl/mutability.md
Normal file
3
src/doc/trpl/mutability.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Mutability
|
||||
|
||||
Coming Soon
|
@ -1,4 +1,4 @@
|
||||
% Unstable Rust
|
||||
% Nightly Rust
|
||||
|
||||
Rust provides three distribution channels for Rust: nightly, beta, and stable.
|
||||
Unstable features are only available on nightly Rust. For more details on this
|
3
src/doc/trpl/operators-and-overloading.md
Normal file
3
src/doc/trpl/operators-and-overloading.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Operators and Overloading
|
||||
|
||||
Coming soon!
|
@ -1,699 +0,0 @@
|
||||
% Pointers
|
||||
|
||||
Rust's pointers are one of its more unique and compelling features. Pointers
|
||||
are also one of the more confusing topics for newcomers to Rust. They can also
|
||||
be confusing for people coming from other languages that support pointers, such
|
||||
as C++. This guide will help you understand this important topic.
|
||||
|
||||
Be sceptical of non-reference pointers in Rust: use them for a deliberate
|
||||
purpose, not just to make the compiler happy. Each pointer type comes with an
|
||||
explanation about when they are appropriate to use. Default to references
|
||||
unless you're in one of those specific situations.
|
||||
|
||||
You may be interested in the [cheat sheet](#cheat-sheet), which gives a quick
|
||||
overview of the types, names, and purpose of the various pointers.
|
||||
|
||||
# An introduction
|
||||
|
||||
If you aren't familiar with the concept of pointers, here's a short
|
||||
introduction. Pointers are a very fundamental concept in systems programming
|
||||
languages, so it's important to understand them.
|
||||
|
||||
## Pointer Basics
|
||||
|
||||
When you create a new variable binding, you're giving a name to a value that's
|
||||
stored at a particular location on the stack. (If you're not familiar with the
|
||||
*heap* vs. *stack*, please check out [this Stack Overflow
|
||||
question](http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap),
|
||||
as the rest of this guide assumes you know the difference.) Like this:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
```
|
||||
|
||||
| location | value |
|
||||
|----------|-------|
|
||||
| 0xd3e030 | 5 |
|
||||
| 0xd3e028 | 8 |
|
||||
|
||||
We're making up memory locations here, they're just sample values. Anyway, the
|
||||
point is that `x`, the name we're using for our variable, corresponds to the
|
||||
memory location `0xd3e030`, and the value at that location is `5`. When we
|
||||
refer to `x`, we get the corresponding value. Hence, `x` is `5`.
|
||||
|
||||
Let's introduce a pointer. In some languages, there is just one type of
|
||||
'pointer,' but in Rust, we have many types. In this case, we'll use a Rust
|
||||
*reference*, which is the simplest kind of pointer.
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
let z = &y;
|
||||
```
|
||||
|
||||
|location | value |
|
||||
|-------- |----------|
|
||||
|0xd3e030 | 5 |
|
||||
|0xd3e028 | 8 |
|
||||
|0xd3e020 | 0xd3e028 |
|
||||
|
||||
See the difference? Rather than contain a value, the value of a pointer is a
|
||||
location in memory. In this case, the location of `y`. `x` and `y` have the
|
||||
type `i32`, but `z` has the type `&i32`. We can print this location using the
|
||||
`{:p}` format string:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
let z = &y;
|
||||
|
||||
println!("{:p}", z);
|
||||
```
|
||||
|
||||
This would print `0xd3e028`, with our fictional memory addresses.
|
||||
|
||||
Because `i32` and `&i32` are different types, we can't, for example, add them
|
||||
together:
|
||||
|
||||
```{rust,ignore}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
let z = &y;
|
||||
|
||||
println!("{}", x + z);
|
||||
```
|
||||
|
||||
This gives us an error:
|
||||
|
||||
```text
|
||||
hello.rs:6:24: 6:25 error: mismatched types: expected `_`, found `&_` (expected integral variable, found &-ptr)
|
||||
hello.rs:6 println!("{}", x + z);
|
||||
^
|
||||
```
|
||||
|
||||
We can *dereference* the pointer by using the `*` operator. Dereferencing a
|
||||
pointer means accessing the value at the location stored in the pointer. This
|
||||
will work:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
let z = &y;
|
||||
|
||||
println!("{}", x + *z);
|
||||
```
|
||||
|
||||
It prints `13`.
|
||||
|
||||
That's it! That's all pointers are: they point to some memory location. Not
|
||||
much else to them. Now that we've discussed the *what* of pointers, let's
|
||||
talk about the *why*.
|
||||
|
||||
## Pointer uses
|
||||
|
||||
Rust's pointers are quite useful, but in different ways than in other systems
|
||||
languages. We'll talk about best practices for Rust pointers later in
|
||||
the guide, but here are some ways that pointers are useful in other languages:
|
||||
|
||||
In C, strings are a pointer to a list of `char`s, ending with a null byte.
|
||||
The only way to use strings is to get quite familiar with pointers.
|
||||
|
||||
Pointers are useful to point to memory locations that are not on the stack. For
|
||||
example, our example used two stack variables, so we were able to give them
|
||||
names. But if we allocated some heap memory, we wouldn't have that name
|
||||
available. In C, `malloc` is used to allocate heap memory, and it returns a
|
||||
pointer.
|
||||
|
||||
As a more general variant of the previous two points, any time you have a
|
||||
structure that can change in size, you need a pointer. You can't tell at
|
||||
compile time how much memory to allocate, so you've gotta use a pointer to
|
||||
point at the memory where it will be allocated, and deal with it at run time.
|
||||
|
||||
Pointers are useful in languages that are pass-by-value, rather than
|
||||
pass-by-reference. Basically, languages can make two choices (this is made
|
||||
up syntax, it's not Rust):
|
||||
|
||||
```text
|
||||
func foo(x) {
|
||||
x = 5
|
||||
}
|
||||
|
||||
func main() {
|
||||
i = 1
|
||||
foo(i)
|
||||
// what is the value of i here?
|
||||
}
|
||||
```
|
||||
|
||||
In languages that are pass-by-value, `foo` will get a copy of `i`, and so
|
||||
the original version of `i` is not modified. At the comment, `i` will still be
|
||||
`1`. In a language that is pass-by-reference, `foo` will get a reference to `i`,
|
||||
and therefore, can change its value. At the comment, `i` will be `5`.
|
||||
|
||||
So what do pointers have to do with this? Well, since pointers point to a
|
||||
location in memory...
|
||||
|
||||
```text
|
||||
func foo(&i32 x) {
|
||||
*x = 5
|
||||
}
|
||||
|
||||
func main() {
|
||||
i = 1
|
||||
foo(&i)
|
||||
// what is the value of i here?
|
||||
}
|
||||
```
|
||||
|
||||
Even in a language which is pass by value, `i` will be `5` at the comment. You
|
||||
see, because the argument `x` is a pointer, we do send a copy over to `foo`,
|
||||
but because it points at a memory location, which we then assign to, the
|
||||
original value is still changed. This pattern is called
|
||||
*pass-reference-by-value*. Tricky!
|
||||
|
||||
## Common pointer problems
|
||||
|
||||
We've talked about pointers, and we've sung their praises. So what's the
|
||||
downside? Well, Rust attempts to mitigate each of these kinds of problems,
|
||||
but here are problems with pointers in other languages:
|
||||
|
||||
Uninitialized pointers can cause a problem. For example, what does this program
|
||||
do?
|
||||
|
||||
```{ignore}
|
||||
&int x;
|
||||
*x = 5; // whoops!
|
||||
```
|
||||
|
||||
Who knows? We just declare a pointer, but don't point it at anything, and then
|
||||
set the memory location that it points at to be `5`. But which location? Nobody
|
||||
knows. This might be harmless, and it might be catastrophic.
|
||||
|
||||
When you combine pointers and functions, it's easy to accidentally invalidate
|
||||
the memory the pointer is pointing to. For example:
|
||||
|
||||
```text
|
||||
func make_pointer(): &int {
|
||||
x = 5;
|
||||
|
||||
return &x;
|
||||
}
|
||||
|
||||
func main() {
|
||||
&int i = make_pointer();
|
||||
*i = 5; // uh oh!
|
||||
}
|
||||
```
|
||||
|
||||
`x` is local to the `make_pointer` function, and therefore, is invalid as soon
|
||||
as `make_pointer` returns. But we return a pointer to its memory location, and
|
||||
so back in `main`, we try to use that pointer, and it's a very similar
|
||||
situation to our first one. Setting invalid memory locations is bad.
|
||||
|
||||
As one last example of a big problem with pointers, *aliasing* can be an
|
||||
issue. Two pointers are said to alias when they point at the same location
|
||||
in memory. Like this:
|
||||
|
||||
```text
|
||||
func mutate(&int i, int j) {
|
||||
*i = j;
|
||||
}
|
||||
|
||||
func main() {
|
||||
x = 5;
|
||||
y = &x;
|
||||
z = &x; //y and z are aliased
|
||||
|
||||
|
||||
run_in_new_thread(mutate, y, 1);
|
||||
run_in_new_thread(mutate, z, 100);
|
||||
|
||||
// what is the value of x here?
|
||||
}
|
||||
```
|
||||
|
||||
In this made-up example, `run_in_new_thread` spins up a new thread, and calls
|
||||
the given function name with its arguments. Since we have two threads, and
|
||||
they're both operating on aliases to `x`, we can't tell which one finishes
|
||||
first, and therefore, the value of `x` is actually non-deterministic. Worse,
|
||||
what if one of them had invalidated the memory location they pointed to? We'd
|
||||
have the same problem as before, where we'd be setting an invalid location.
|
||||
|
||||
## Conclusion
|
||||
|
||||
That's a basic overview of pointers as a general concept. As we alluded to
|
||||
before, Rust has different kinds of pointers, rather than just one, and
|
||||
mitigates all of the problems that we talked about, too. This does mean that
|
||||
Rust pointers are slightly more complicated than in other languages, but
|
||||
it's worth it to not have the problems that simple pointers have.
|
||||
|
||||
# References
|
||||
|
||||
The most basic type of pointer that Rust has is called a *reference*. Rust
|
||||
references look like this:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
println!("{}", *y);
|
||||
println!("{:p}", y);
|
||||
println!("{}", y);
|
||||
```
|
||||
|
||||
We'd say "`y` is a reference to `x`." The first `println!` prints out the
|
||||
value of `y`'s referent by using the dereference operator, `*`. The second
|
||||
one prints out the memory location that `y` points to, by using the pointer
|
||||
format string. The third `println!` *also* prints out the value of `y`'s
|
||||
referent, because `println!` will automatically dereference it for us.
|
||||
|
||||
Here's a function that takes a reference:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
You can also use `&` as an operator to create a reference, so we can
|
||||
call this function in two different ways:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
|
||||
fn main() {
|
||||
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
println!("{}", succ(y));
|
||||
println!("{}", succ(&x));
|
||||
}
|
||||
```
|
||||
|
||||
Both of these `println!`s will print out `6`.
|
||||
|
||||
Of course, if this were real code, we wouldn't bother with the reference, and
|
||||
just write:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: i32) -> i32 { x + 1 }
|
||||
```
|
||||
|
||||
References are immutable by default:
|
||||
|
||||
```{rust,ignore}
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
*y = 5; // error: cannot assign to immutable borrowed content `*y`
|
||||
```
|
||||
|
||||
They can be made mutable with `mut`, but only if its referent is also mutable.
|
||||
This works:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5;
|
||||
let y = &mut x;
|
||||
```
|
||||
|
||||
This does not:
|
||||
|
||||
```{rust,ignore}
|
||||
let x = 5;
|
||||
let y = &mut x; // error: cannot borrow immutable local variable `x` as mutable
|
||||
```
|
||||
|
||||
Immutable pointers are allowed to alias:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
let z = &x;
|
||||
```
|
||||
|
||||
Mutable ones, however, are not:
|
||||
|
||||
```{rust,ignore}
|
||||
let mut x = 5;
|
||||
let y = &mut x;
|
||||
let z = &mut x; // error: cannot borrow `x` as mutable more than once at a time
|
||||
```
|
||||
|
||||
Despite their complete safety, a reference's representation at runtime is the
|
||||
same as that of an ordinary pointer in a C program. They introduce zero
|
||||
overhead. The compiler does all safety checks at compile time. The theory that
|
||||
allows for this was originally called *region pointers*. Region pointers
|
||||
evolved into what we know today as *lifetimes*.
|
||||
|
||||
Here's the simple explanation: would you expect this code to compile?
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
println!("{}", x);
|
||||
let x = 5;
|
||||
}
|
||||
```
|
||||
|
||||
Probably not. That's because you know that the name `x` is valid from where
|
||||
it's declared to when it goes out of scope. In this case, that's the end of
|
||||
the `main` function. So you know this code will cause an error. We call this
|
||||
duration a *lifetime*. Let's try a more complex example:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
|
||||
if x < 10 {
|
||||
let y = &x;
|
||||
|
||||
println!("Oh no: {}", y);
|
||||
return;
|
||||
}
|
||||
|
||||
x -= 1;
|
||||
|
||||
println!("Oh no: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Here, we're borrowing a pointer to `x` inside of the `if`. The compiler, however,
|
||||
is able to determine that that pointer will go out of scope without `x` being
|
||||
mutated, and therefore, lets us pass. This wouldn't work:
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
|
||||
if x < 10 {
|
||||
let y = &x;
|
||||
|
||||
x -= 1;
|
||||
|
||||
println!("Oh no: {}", y);
|
||||
return;
|
||||
}
|
||||
|
||||
x -= 1;
|
||||
|
||||
println!("Oh no: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
It gives this error:
|
||||
|
||||
```text
|
||||
test.rs:7:9: 7:15 error: cannot assign to `x` because it is borrowed
|
||||
test.rs:7 x -= 1;
|
||||
^~~~~~
|
||||
test.rs:5:18: 5:19 note: borrow of `x` occurs here
|
||||
test.rs:5 let y = &x;
|
||||
^
|
||||
```
|
||||
|
||||
As you might guess, this kind of analysis is complex for a human, and therefore
|
||||
hard for a computer, too! There is an entire [guide devoted to references, ownership,
|
||||
and lifetimes](ownership.html) that goes into this topic in
|
||||
great detail, so if you want the full details, check that out.
|
||||
|
||||
## Best practices
|
||||
|
||||
In general, prefer stack allocation over heap allocation. Using references to
|
||||
stack allocated information is preferred whenever possible. Therefore,
|
||||
references are the default pointer type you should use, unless you have a
|
||||
specific reason to use a different type. The other types of pointers cover when
|
||||
they're appropriate to use in their own best practices sections.
|
||||
|
||||
Use references when you want to use a pointer, but do not want to take ownership.
|
||||
References just borrow ownership, which is more polite if you don't need the
|
||||
ownership. In other words, prefer:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
to
|
||||
|
||||
```{rust}
|
||||
fn succ(x: Box<i32>) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
As a corollary to that rule, references allow you to accept a wide variety of
|
||||
other pointers, and so are useful so that you don't have to write a number
|
||||
of variants per pointer. In other words, prefer:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
to
|
||||
|
||||
```{rust}
|
||||
use std::rc::Rc;
|
||||
|
||||
fn box_succ(x: Box<i32>) -> i32 { *x + 1 }
|
||||
|
||||
fn rc_succ(x: Rc<i32>) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
Note that the caller of your function will have to modify their calls slightly:
|
||||
|
||||
```{rust}
|
||||
use std::rc::Rc;
|
||||
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
|
||||
let ref_x = &5;
|
||||
let box_x = Box::new(5);
|
||||
let rc_x = Rc::new(5);
|
||||
|
||||
succ(ref_x);
|
||||
succ(&*box_x);
|
||||
succ(&*rc_x);
|
||||
```
|
||||
|
||||
The initial `*` dereferences the pointer, and then `&` takes a reference to
|
||||
those contents.
|
||||
|
||||
# Boxes
|
||||
|
||||
`Box<T>` is Rust's *boxed pointer* type. Boxes provide the simplest form of
|
||||
heap allocation in Rust. Creating a box looks like this:
|
||||
|
||||
```{rust}
|
||||
let x = Box::new(5);
|
||||
```
|
||||
|
||||
Boxes are heap allocated and they are deallocated automatically by Rust when
|
||||
they go out of scope:
|
||||
|
||||
```{rust}
|
||||
{
|
||||
let x = Box::new(5);
|
||||
|
||||
// stuff happens
|
||||
|
||||
} // x is destructed and its memory is free'd here
|
||||
```
|
||||
|
||||
However, boxes do _not_ use reference counting or garbage collection. Boxes are
|
||||
what's called an *affine type*. This means that the Rust compiler, at compile
|
||||
time, determines when the box comes into and goes out of scope, and inserts the
|
||||
appropriate calls there.
|
||||
|
||||
You don't need to fully grok the theory of affine types to grok boxes, though.
|
||||
As a rough approximation, you can treat this Rust code:
|
||||
|
||||
```{rust}
|
||||
{
|
||||
let x = Box::new(5);
|
||||
|
||||
// stuff happens
|
||||
}
|
||||
```
|
||||
|
||||
As being similar to this C code:
|
||||
|
||||
```c
|
||||
{
|
||||
int *x;
|
||||
x = (int *)malloc(sizeof(int));
|
||||
*x = 5;
|
||||
|
||||
// stuff happens
|
||||
|
||||
free(x);
|
||||
}
|
||||
```
|
||||
|
||||
Of course, this is a 10,000 foot view. It leaves out destructors, for example.
|
||||
But the general idea is correct: you get the semantics of `malloc`/`free`, but
|
||||
with some improvements:
|
||||
|
||||
1. It's impossible to allocate the incorrect amount of memory, because Rust
|
||||
figures it out from the types.
|
||||
2. You cannot forget to `free` memory you've allocated, because Rust does it
|
||||
for you.
|
||||
3. Rust ensures that this `free` happens at the right time, when it is truly
|
||||
not used. Use-after-free is not possible.
|
||||
4. Rust enforces that no other writeable pointers alias to this heap memory,
|
||||
which means writing to an invalid pointer is not possible.
|
||||
|
||||
See the section on references or the [ownership guide](ownership.html)
|
||||
for more detail on how lifetimes work.
|
||||
|
||||
Using boxes and references together is very common. For example:
|
||||
|
||||
```{rust}
|
||||
fn add_one(x: &i32) -> i32 {
|
||||
*x + 1
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(5);
|
||||
|
||||
println!("{}", add_one(&*x));
|
||||
}
|
||||
```
|
||||
|
||||
In this case, Rust knows that `x` is being *borrowed* by the `add_one()`
|
||||
function, and since it's only reading the value, allows it.
|
||||
|
||||
We can borrow `x` as read-only multiple times, even simultaneously:
|
||||
|
||||
```{rust}
|
||||
fn add(x: &i32, y: &i32) -> i32 {
|
||||
*x + *y
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(5);
|
||||
|
||||
println!("{}", add(&*x, &*x));
|
||||
println!("{}", add(&*x, &*x));
|
||||
}
|
||||
```
|
||||
|
||||
We can mutably borrow `x` multiple times, but only if x itself is mutable, and
|
||||
it may not be *simultaneously* borrowed:
|
||||
|
||||
```{rust,ignore}
|
||||
fn increment(x: &mut i32) {
|
||||
*x += 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// If variable x is not "mut", this will not compile
|
||||
let mut x = Box::new(5);
|
||||
|
||||
increment(&mut x);
|
||||
increment(&mut x);
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Notice the signature of `increment()` requests a mutable reference.
|
||||
|
||||
## Best practices
|
||||
|
||||
Boxes are most appropriate to use when defining recursive data structures.
|
||||
|
||||
### Recursive data structures
|
||||
|
||||
Sometimes, you need a recursive data structure. The simplest is known as a
|
||||
*cons list*:
|
||||
|
||||
|
||||
```{rust}
|
||||
#[derive(Debug)]
|
||||
enum List<T> {
|
||||
Cons(T, Box<List<T>>),
|
||||
Nil,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Cons(3, Box::new(List::Nil))))));
|
||||
println!("{:?}", list);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```text
|
||||
Cons(1, Box(Cons(2, Box(Cons(3, Box(Nil))))))
|
||||
```
|
||||
|
||||
The reference to another `List` inside of the `Cons` enum variant must be a box,
|
||||
because we don't know the length of the list. Because we don't know the length,
|
||||
we don't know the size, and therefore, we need to heap allocate our list.
|
||||
|
||||
Working with recursive or other unknown-sized data structures is the primary
|
||||
use-case for boxes.
|
||||
|
||||
# Rc and Arc
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
## Best practices
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
# Raw Pointers
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
## Best practices
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
# Creating your own Pointers
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
## Best practices
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
# Patterns and `ref`
|
||||
|
||||
When you're trying to match something that's stored in a pointer, there may be
|
||||
a situation where matching directly isn't the best option available. Let's see
|
||||
how to properly handle this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn possibly_print(x: &Option<String>) {
|
||||
match *x {
|
||||
// BAD: cannot move out of a `&`
|
||||
Some(s) => println!("{}", s)
|
||||
|
||||
// GOOD: instead take a reference into the memory of the `Option`
|
||||
Some(ref s) => println!("{}", *s),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `ref s` here means that `s` will be of type `&String`, rather than type
|
||||
`String`.
|
||||
|
||||
This is important when the type you're trying to get access to has a destructor
|
||||
and you don't want to move it, you just want a reference to it.
|
||||
|
||||
# Cheat Sheet
|
||||
|
||||
Here's a quick rundown of Rust's pointer types:
|
||||
|
||||
| Type | Name | Summary |
|
||||
|--------------|---------------------|---------------------------------------------------------------------|
|
||||
| `&T` | Reference | Allows one or more references to read `T` |
|
||||
| `&mut T` | Mutable Reference | Allows a single reference to read and write `T` |
|
||||
| `Box<T>` | Box | Heap allocated `T` with a single owner that may read and write `T`. |
|
||||
| `Rc<T>` | "arr cee" pointer | Heap allocated `T` with many readers |
|
||||
| `Arc<T>` | Arc pointer | Same as above, but safe sharing across threads |
|
||||
| `*const T` | Raw pointer | Unsafe read access to `T` |
|
||||
| `*mut T` | Mutable raw pointer | Unsafe read and write access to `T` |
|
||||
|
||||
# Related resources
|
||||
|
||||
* [API documentation for Box](../std/boxed/index.html)
|
||||
* [Ownership guide](ownership.html)
|
||||
* [Cyclone paper on regions](http://www.cs.umd.edu/projects/cyclone/papers/cyclone-regions.pdf), which inspired Rust's lifetime system
|
3
src/doc/trpl/primitive-types.md
Normal file
3
src/doc/trpl/primitive-types.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Primitive Types
|
||||
|
||||
Coming Soon!
|
3
src/doc/trpl/references-and-borrowing.md
Normal file
3
src/doc/trpl/references-and-borrowing.md
Normal file
@ -0,0 +1,3 @@
|
||||
% References and Borrowing
|
||||
|
||||
Coming Soon!
|
21
src/doc/trpl/slices.md
Normal file
21
src/doc/trpl/slices.md
Normal file
@ -0,0 +1,21 @@
|
||||
% Slices
|
||||
|
||||
A *slice* is a reference to (or "view" into) an array. They are useful for
|
||||
allowing safe, efficient access to a portion of an array without copying. For
|
||||
example, you might want to reference just one line of a file read into memory.
|
||||
By nature, a slice is not created directly, but from an existing variable.
|
||||
Slices have a length, can be mutable or not, and in many ways behave like
|
||||
arrays:
|
||||
|
||||
```{rust}
|
||||
let a = [0, 1, 2, 3, 4];
|
||||
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
|
||||
|
||||
for e in middle.iter() {
|
||||
println!("{}", e); // Prints 1, 2, 3
|
||||
}
|
||||
```
|
||||
|
||||
You can also take a slice of a vector, `String`, or `&str`, because they are
|
||||
backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover
|
||||
generics.
|
3
src/doc/trpl/static.md
Normal file
3
src/doc/trpl/static.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `static`
|
||||
|
||||
Coming soon!
|
49
src/doc/trpl/structs.md
Normal file
49
src/doc/trpl/structs.md
Normal file
@ -0,0 +1,49 @@
|
||||
% Structs
|
||||
|
||||
A struct is another form of a *record type*, just like a tuple. There's a
|
||||
difference: structs give each element that they contain a name, called a
|
||||
*field* or a *member*. Check it out:
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let origin = Point { x: 0, y: 0 }; // origin: Point
|
||||
|
||||
println!("The origin is at ({}, {})", origin.x, origin.y);
|
||||
}
|
||||
```
|
||||
|
||||
There's a lot going on here, so let's break it down. We declare a struct with
|
||||
the `struct` keyword, and then with a name. By convention, structs begin with a
|
||||
capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`.
|
||||
|
||||
We can create an instance of our struct via `let`, as usual, but we use a `key:
|
||||
value` style syntax to set each field. The order doesn't need to be the same as
|
||||
in the original declaration.
|
||||
|
||||
Finally, because fields have names, we can access the field through dot
|
||||
notation: `origin.x`.
|
||||
|
||||
The values in structs are immutable by default, like other bindings in Rust.
|
||||
Use `mut` to make them mutable:
|
||||
|
||||
```{rust}
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut point = Point { x: 0, y: 0 };
|
||||
|
||||
point.x = 5;
|
||||
|
||||
println!("The point is at ({}, {})", point.x, point.y);
|
||||
}
|
||||
```
|
||||
|
||||
This will print `The point is at (5, 0)`.
|
1
src/doc/trpl/syntax-and-semantics.md
Normal file
1
src/doc/trpl/syntax-and-semantics.md
Normal file
@ -0,0 +1 @@
|
||||
% Syntax and Semantics
|
3
src/doc/trpl/the-stack-and-the-heap.md
Normal file
3
src/doc/trpl/the-stack-and-the-heap.md
Normal file
@ -0,0 +1,3 @@
|
||||
% The Stack and the Heap
|
||||
|
||||
Coming Soon
|
@ -1,91 +0,0 @@
|
||||
% Tracing Macros
|
||||
|
||||
The `trace_macros` feature allows you to use a special feature: tracing macro
|
||||
invocations.
|
||||
|
||||
In the advanced macros chapter, we defined a `bct` macro:
|
||||
|
||||
```rust
|
||||
macro_rules! bct {
|
||||
// cmd 0: d ... => ...
|
||||
(0, $($ps:tt),* ; $_d:tt)
|
||||
=> (bct!($($ps),*, 0 ; ));
|
||||
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 0 ; $($ds),*));
|
||||
|
||||
// cmd 1p: 1 ... => 1 ... p
|
||||
(1, $p:tt, $($ps:tt),* ; 1)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $p));
|
||||
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
|
||||
|
||||
// cmd 1p: 0 ... => 0 ...
|
||||
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
|
||||
// halt on empty data string
|
||||
( $($ps:tt),* ; )
|
||||
=> (());
|
||||
}
|
||||
```
|
||||
|
||||
This is pretty complex! we can see the output
|
||||
|
||||
```rust,ignore
|
||||
#![feature(trace_macros)]
|
||||
|
||||
macro_rules! bct {
|
||||
// cmd 0: d ... => ...
|
||||
(0, $($ps:tt),* ; $_d:tt)
|
||||
=> (bct!($($ps),*, 0 ; ));
|
||||
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 0 ; $($ds),*));
|
||||
|
||||
// cmd 1p: 1 ... => 1 ... p
|
||||
(1, $p:tt, $($ps:tt),* ; 1)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $p));
|
||||
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
|
||||
|
||||
// cmd 1p: 0 ... => 0 ...
|
||||
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
|
||||
// halt on empty data string
|
||||
( $($ps:tt),* ; )
|
||||
=> (());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
trace_macros!(true);
|
||||
|
||||
bct!(0, 0, 1, 1, 1 ; 1, 0, 1);
|
||||
}
|
||||
```
|
||||
|
||||
This will print out a wall of text:
|
||||
|
||||
```text
|
||||
bct! { 0 , 0 , 1 , 1 , 1 ; 1 , 0 , 1 }
|
||||
bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 }
|
||||
bct! { 1 , 1 , 1 , 0 , 0 ; 1 }
|
||||
bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 1 }
|
||||
bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 1 , 0 }
|
||||
bct! { 1 , 1 , 1 , 0 , 0 ; 1 , 0 }
|
||||
bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 0 , 1 }
|
||||
bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 0 , 1 , 0 }
|
||||
bct! { 1 , 1 , 1 , 0 , 0 ; 0 , 1 , 0 }
|
||||
bct! { 1 , 0 , 0 , 1 , 1 ; 0 , 1 , 0 }
|
||||
bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 , 0 }
|
||||
```
|
||||
|
||||
And eventually, error:
|
||||
|
||||
```text
|
||||
18:45 error: recursion limit reached while expanding the macro `bct`
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
The `trace_macros!` call is what produces this output, showing how we match
|
||||
each time.
|
@ -1,4 +1,4 @@
|
||||
% Static and Dynamic Dispatch
|
||||
% Trait Objects
|
||||
|
||||
When code involves polymorphism, there needs to be a mechanism to determine
|
||||
which specific version is actually run. This is called 'dispatch.' There are
|
56
src/doc/trpl/tuple-structs.md
Normal file
56
src/doc/trpl/tuple-structs.md
Normal file
@ -0,0 +1,56 @@
|
||||
% Tuple Structs
|
||||
|
||||
Rust has another data type that's like a hybrid between a tuple and a struct,
|
||||
called a *tuple struct*. Tuple structs do have a name, but their fields don't:
|
||||
|
||||
```{rust}
|
||||
struct Color(i32, i32, i32);
|
||||
struct Point(i32, i32, i32);
|
||||
```
|
||||
|
||||
These two will not be equal, even if they have the same values:
|
||||
|
||||
```{rust}
|
||||
# struct Color(i32, i32, i32);
|
||||
# struct Point(i32, i32, i32);
|
||||
let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
```
|
||||
|
||||
It is almost always better to use a struct than a tuple struct. We would write
|
||||
`Color` and `Point` like this instead:
|
||||
|
||||
```{rust}
|
||||
struct Color {
|
||||
red: i32,
|
||||
blue: i32,
|
||||
green: i32,
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
```
|
||||
|
||||
Now, we have actual names, rather than positions. Good names are important,
|
||||
and with a struct, we have actual names.
|
||||
|
||||
There _is_ one case when a tuple struct is very useful, though, and that's a
|
||||
tuple struct with only one element. We call this the *newtype* pattern, because
|
||||
it allows you to create a new type, distinct from that of its contained value
|
||||
and expressing its own semantic meaning:
|
||||
|
||||
```{rust}
|
||||
struct Inches(i32);
|
||||
|
||||
let length = Inches(10);
|
||||
|
||||
let Inches(integer_length) = length;
|
||||
println!("length is {} inches", integer_length);
|
||||
```
|
||||
|
||||
As you can see here, you can extract the inner integer type through a
|
||||
destructuring `let`, as we discussed previously in 'tuples.' In this case, the
|
||||
`let Inches(integer_length)` assigns `10` to `integer_length`.
|
97
src/doc/trpl/tuples.md
Normal file
97
src/doc/trpl/tuples.md
Normal file
@ -0,0 +1,97 @@
|
||||
% Tuples
|
||||
|
||||
The first compound data type we're going to talk about is called the *tuple*.
|
||||
A tuple is an ordered list of fixed size. Like this:
|
||||
|
||||
```rust
|
||||
let x = (1, "hello");
|
||||
```
|
||||
|
||||
The parentheses and commas form this two-length tuple. Here's the same code, but
|
||||
with the type annotated:
|
||||
|
||||
```rust
|
||||
let x: (i32, &str) = (1, "hello");
|
||||
```
|
||||
|
||||
As you can see, the type of a tuple looks just like the tuple, but with each
|
||||
position having a type name rather than the value. Careful readers will also
|
||||
note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple.
|
||||
You have briefly seen `&str` used as a type before, and we'll discuss the
|
||||
details of strings later. In systems programming languages, strings are a bit
|
||||
more complex than in other languages. For now, just read `&str` as a *string
|
||||
slice*, and we'll learn more soon.
|
||||
|
||||
You can access the fields in a tuple through a *destructuring let*. Here's
|
||||
an example:
|
||||
|
||||
```rust
|
||||
let (x, y, z) = (1, 2, 3);
|
||||
|
||||
println!("x is {}", x);
|
||||
```
|
||||
|
||||
Remember before when I said the left-hand side of a `let` statement was more
|
||||
powerful than just assigning a binding? Here we are. We can put a pattern on
|
||||
the left-hand side of the `let`, and if it matches up to the right-hand side,
|
||||
we can assign multiple bindings at once. In this case, `let` "destructures,"
|
||||
or "breaks up," the tuple, and assigns the bits to three bindings.
|
||||
|
||||
This pattern is very powerful, and we'll see it repeated more later.
|
||||
|
||||
There are also a few things you can do with a tuple as a whole, without
|
||||
destructuring. You can assign one tuple into another, if they have the same
|
||||
contained types and [arity]. Tuples have the same arity when they have the same
|
||||
length.
|
||||
|
||||
```rust
|
||||
let mut x = (1, 2); // x: (i32, i32)
|
||||
let y = (2, 3); // y: (i32, i32)
|
||||
|
||||
x = y;
|
||||
```
|
||||
|
||||
You can also check for equality with `==`. Again, this will only compile if the
|
||||
tuples have the same type.
|
||||
|
||||
```rust
|
||||
let x = (1, 2, 3);
|
||||
let y = (2, 2, 4);
|
||||
|
||||
if x == y {
|
||||
println!("yes");
|
||||
} else {
|
||||
println!("no");
|
||||
}
|
||||
```
|
||||
|
||||
This will print `no`, because some of the values aren't equal.
|
||||
|
||||
Note that the order of the values is considered when checking for equality,
|
||||
so the following example will also print `no`.
|
||||
|
||||
```rust
|
||||
let x = (1, 2, 3);
|
||||
let y = (2, 1, 3);
|
||||
|
||||
if x == y {
|
||||
println!("yes");
|
||||
} else {
|
||||
println!("no");
|
||||
}
|
||||
```
|
||||
|
||||
One other use of tuples is to return multiple values from a function:
|
||||
|
||||
```rust
|
||||
fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }
|
||||
|
||||
fn main() {
|
||||
let (x, y) = next_two(5);
|
||||
println!("x, y = {}, {}", x, y);
|
||||
}
|
||||
```
|
||||
|
||||
Even though Rust functions can only return one value, a tuple *is* one value,
|
||||
that happens to be made up of more than one value. You can also see in this
|
||||
example how you can destructure a pattern returned by a function, as well.
|
3
src/doc/trpl/type-aliases.md
Normal file
3
src/doc/trpl/type-aliases.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `type` Aliases
|
||||
|
||||
Coming soon
|
3
src/doc/trpl/ufcs.md
Normal file
3
src/doc/trpl/ufcs.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Universal Function Call Syntax
|
||||
|
||||
Coming soon
|
@ -1,4 +1,4 @@
|
||||
% Unsafe and Low-Level Code
|
||||
% Unsafe Code
|
||||
|
||||
# Introduction
|
||||
|
3
src/doc/trpl/unsized-types.md
Normal file
3
src/doc/trpl/unsized-types.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Unsized Types
|
||||
|
||||
Coming Soon!
|
33
src/doc/trpl/vectors.md
Normal file
33
src/doc/trpl/vectors.md
Normal file
@ -0,0 +1,33 @@
|
||||
% Vectors
|
||||
|
||||
A *vector* is a dynamic or "growable" array, implemented as the standard
|
||||
library type [`Vec<T>`](../std/vec/) (we'll talk about what the `<T>` means
|
||||
later). Vectors always allocate their data on the heap. Vectors are to slices
|
||||
what `String` is to `&str`. You can create them with the `vec!` macro:
|
||||
|
||||
```{rust}
|
||||
let v = vec![1, 2, 3]; // v: Vec<i32>
|
||||
```
|
||||
|
||||
(Notice that unlike the `println!` macro we've used in the past, we use square
|
||||
brackets `[]` with `vec!`. Rust allows you to use either in either situation,
|
||||
this is just convention.)
|
||||
|
||||
There's an alternate form of `vec!` for repeating an initial value:
|
||||
|
||||
```
|
||||
let v = vec![0; 10]; // ten zeroes
|
||||
```
|
||||
|
||||
You can get the length of, iterate over, and subscript vectors just like
|
||||
arrays. In addition, (mutable) vectors can grow automatically:
|
||||
|
||||
```{rust}
|
||||
let mut nums = vec![1, 2, 3]; // mut nums: Vec<i32>
|
||||
|
||||
nums.push(4);
|
||||
|
||||
println!("The length of nums is now {}", nums.len()); // Prints 4
|
||||
```
|
||||
|
||||
Vectors have many more useful methods.
|
@ -1,54 +1,4 @@
|
||||
% Looping
|
||||
|
||||
Looping is the last basic construct that we haven't learned yet in Rust. Rust has
|
||||
two main looping constructs: `for` and `while`.
|
||||
|
||||
## `for`
|
||||
|
||||
The `for` loop is used to loop a particular number of times. Rust's `for` loops
|
||||
work a bit differently than in other systems languages, however. Rust's `for`
|
||||
loop doesn't look like this "C-style" `for` loop:
|
||||
|
||||
```{c}
|
||||
for (x = 0; x < 10; x++) {
|
||||
printf( "%d\n", x );
|
||||
}
|
||||
```
|
||||
|
||||
Instead, it looks like this:
|
||||
|
||||
```{rust}
|
||||
for x in 0..10 {
|
||||
println!("{}", x); // x: i32
|
||||
}
|
||||
```
|
||||
|
||||
In slightly more abstract terms,
|
||||
|
||||
```{ignore}
|
||||
for var in expression {
|
||||
code
|
||||
}
|
||||
```
|
||||
|
||||
The expression is an iterator, which we will discuss in more depth later in the
|
||||
guide. The iterator gives back a series of elements. Each element is one
|
||||
iteration of the loop. That value is then bound to the name `var`, which is
|
||||
valid for the loop body. Once the body is over, the next value is fetched from
|
||||
the iterator, and we loop another time. When there are no more values, the
|
||||
`for` loop is over.
|
||||
|
||||
In our example, `0..10` is an expression that takes a start and an end position,
|
||||
and gives an iterator over those values. The upper bound is exclusive, though,
|
||||
so our loop will print `0` through `9`, not `10`.
|
||||
|
||||
Rust does not have the "C-style" `for` loop on purpose. Manually controlling
|
||||
each element of the loop is complicated and error prone, even for experienced C
|
||||
developers.
|
||||
|
||||
We'll talk more about `for` when we cover *iterators*, later in the Guide.
|
||||
|
||||
## `while`
|
||||
% `while` loops
|
||||
|
||||
The other kind of looping construct in Rust is the `while` loop. It looks like
|
||||
this:
|
@ -10,51 +10,134 @@
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
// Error messages for EXXXX errors.
|
||||
// Each message should start and end with a new line, and be wrapped to 80 characters.
|
||||
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
|
||||
register_long_diagnostics! {
|
||||
E0001: r##"
|
||||
This error suggests that the expression arm corresponding to the noted pattern
|
||||
will never be reached as for all possible values of the expression being matched,
|
||||
one of the preceding patterns will match.
|
||||
|
||||
This means that perhaps some of the preceding patterns are too general, this
|
||||
one is too specific or the ordering is incorrect.
|
||||
E0001: r##"
|
||||
This error suggests that the expression arm corresponding to the noted pattern
|
||||
will never be reached as for all possible values of the expression being
|
||||
matched, one of the preceding patterns will match.
|
||||
|
||||
This means that perhaps some of the preceding patterns are too general, this one
|
||||
is too specific or the ordering is incorrect.
|
||||
"##,
|
||||
|
||||
E0003: r##"
|
||||
Not-a-Number (NaN) values can not be compared for equality and hence can never match
|
||||
the input to a match expression. To match against NaN values, you should instead use
|
||||
the `is_nan` method in a guard, as in: x if x.is_nan() => ...
|
||||
E0002: r##"
|
||||
This error indicates that an empty match expression is illegal because the type
|
||||
it is matching on is non-empty (there exist values of this type). In safe code
|
||||
it is impossible to create an instance of an empty type, so empty match
|
||||
expressions are almost never desired. This error is typically fixed by adding
|
||||
one or more cases to the match expression.
|
||||
|
||||
An example of an empty type is `enum Empty { }`.
|
||||
"##,
|
||||
|
||||
E0004: r##"
|
||||
This error indicates that the compiler can not guarantee a matching pattern for one
|
||||
or more possible inputs to a match expression. Guaranteed matches are required in order
|
||||
to assign values to match expressions, or alternatively, determine the flow of execution.
|
||||
|
||||
If you encounter this error you must alter your patterns so that every possible value of
|
||||
the input type is matched. For types with a small number of variants (like enums) you
|
||||
should probably cover all cases explicitly. Alternatively, the underscore `_` wildcard
|
||||
pattern can be added after all other patterns to match "anything else".
|
||||
E0003: r##"
|
||||
Not-a-Number (NaN) values cannot be compared for equality and hence can never
|
||||
match the input to a match expression. To match against NaN values, you should
|
||||
instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ...
|
||||
"##,
|
||||
|
||||
// FIXME: Remove duplication here?
|
||||
E0005: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
E0004: r##"
|
||||
This error indicates that the compiler cannot guarantee a matching pattern for
|
||||
one or more possible inputs to a match expression. Guaranteed matches are
|
||||
required in order to assign values to match expressions, or alternatively,
|
||||
determine the flow of execution.
|
||||
|
||||
If you encounter this error you must alter your patterns so that every possible
|
||||
value of the input type is matched. For types with a small number of variants
|
||||
(like enums) you should probably cover all cases explicitly. Alternatively, the
|
||||
underscore `_` wildcard pattern can be added after all other patterns to match
|
||||
"anything else".
|
||||
"##,
|
||||
|
||||
E0006: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
// FIXME: Remove duplication here?
|
||||
E0005: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
"##,
|
||||
|
||||
E0006: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
"##,
|
||||
|
||||
E0007: r##"
|
||||
This error indicates that the bindings in a match arm would require a value to
|
||||
be moved into more than one location, thus violating unique ownership. Code like
|
||||
the following is invalid as it requires the entire Option<String> to be moved
|
||||
into a variable called `op_string` while simultaneously requiring the inner
|
||||
String to be moved into a variable called `s`.
|
||||
|
||||
let x = Some("s".to_string());
|
||||
match x {
|
||||
op_string @ Some(s) => ...
|
||||
None => ...
|
||||
}
|
||||
|
||||
See also Error 303.
|
||||
"##,
|
||||
|
||||
E0008: r##"
|
||||
Names bound in match arms retain their type in pattern guards. As such, if a
|
||||
name is bound by move in a pattern, it should also be moved to wherever it is
|
||||
referenced in the pattern guard code. Doing so however would prevent the name
|
||||
from being available in the body of the match arm. Consider the following:
|
||||
|
||||
match Some("hi".to_string()) {
|
||||
Some(s) if s.len() == 0 => // use s.
|
||||
...
|
||||
}
|
||||
|
||||
The variable `s` has type String, and its use in the guard is as a variable of
|
||||
type String. The guard code effectively executes in a separate scope to the body
|
||||
of the arm, so the value would be moved into this anonymous scope and therefore
|
||||
become unavailable in the body of the arm. Although this example seems
|
||||
innocuous, the problem is most clear when considering functions that take their
|
||||
argument by value.
|
||||
|
||||
match Some("hi".to_string()) {
|
||||
Some(s) if { drop(s); false } => (),
|
||||
Some(s) => // use s.
|
||||
...
|
||||
}
|
||||
|
||||
The value would be dropped in the guard then become unavailable not only in the
|
||||
body of that arm but also in all subsequent arms! The solution is to bind by
|
||||
reference when using guards or refactor the entire expression, perhaps by
|
||||
putting the condition inside the body of the arm.
|
||||
"##,
|
||||
|
||||
E0303: r##"
|
||||
In certain cases it is possible for sub-bindings to violate memory safety.
|
||||
Updates to the borrow checker in a future version of Rust may remove this
|
||||
restriction, but for now patterns must be rewritten without sub-bindings.
|
||||
|
||||
// Code like this...
|
||||
match Some(5) {
|
||||
ref op_num @ Some(num) => ...
|
||||
None => ...
|
||||
}
|
||||
|
||||
// ... should be updated to code like this.
|
||||
match Some(5) {
|
||||
Some(num) => {
|
||||
let op_num = &Some(num);
|
||||
...
|
||||
}
|
||||
None => ...
|
||||
}
|
||||
|
||||
See also https://github.com/rust-lang/rust/issues/14587
|
||||
"##
|
||||
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
E0002,
|
||||
E0007,
|
||||
E0008,
|
||||
E0009,
|
||||
E0010,
|
||||
E0011,
|
||||
@ -117,7 +200,6 @@ register_diagnostics! {
|
||||
E0300, // unexpanded macro
|
||||
E0301, // cannot mutable borrow in a pattern guard
|
||||
E0302, // cannot assign in a pattern guard
|
||||
E0303, // pattern bindings are not allowed after an `@`
|
||||
E0304, // expected signed integer constant
|
||||
E0305, // expected constant
|
||||
E0306, // expected positive integer for repeat count
|
||||
|
@ -277,7 +277,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
|
||||
Some(ref code) => {
|
||||
match descriptions.find_description(&code[..]) {
|
||||
Some(ref description) => {
|
||||
println!("{}", description);
|
||||
// Slice off the leading newline and print.
|
||||
print!("{}", &description[1..]);
|
||||
}
|
||||
None => {
|
||||
early_error(&format!("no extended information for {}", code));
|
||||
|
@ -112,58 +112,6 @@
|
||||
//! });
|
||||
//! rx.recv().unwrap();
|
||||
//! ```
|
||||
//!
|
||||
//! Reading from a channel with a timeout requires to use a Timer together
|
||||
//! with the channel. You can use the `select!` macro to select either and
|
||||
//! handle the timeout case. This first example will break out of the loop
|
||||
//! after 10 seconds no matter what:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # #![feature(std_misc, old_io)]
|
||||
//! use std::sync::mpsc::channel;
|
||||
//! use std::old_io::timer::Timer;
|
||||
//! use std::time::Duration;
|
||||
//!
|
||||
//! let (tx, rx) = channel::<i32>();
|
||||
//! let mut timer = Timer::new().unwrap();
|
||||
//! let timeout = timer.oneshot(Duration::seconds(10));
|
||||
//!
|
||||
//! loop {
|
||||
//! select! {
|
||||
//! val = rx.recv() => println!("Received {}", val.unwrap()),
|
||||
//! _ = timeout.recv() => {
|
||||
//! println!("timed out, total time was more than 10 seconds");
|
||||
//! break;
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This second example is more costly since it allocates a new timer every
|
||||
//! time a message is received, but it allows you to timeout after the channel
|
||||
//! has been inactive for 5 seconds:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # #![feature(std_misc, old_io)]
|
||||
//! use std::sync::mpsc::channel;
|
||||
//! use std::old_io::timer::Timer;
|
||||
//! use std::time::Duration;
|
||||
//!
|
||||
//! let (tx, rx) = channel::<i32>();
|
||||
//! let mut timer = Timer::new().unwrap();
|
||||
//!
|
||||
//! loop {
|
||||
//! let timeout = timer.oneshot(Duration::seconds(5));
|
||||
//!
|
||||
//! select! {
|
||||
//! val = rx.recv() => println!("Received {}", val.unwrap()),
|
||||
//! _ = timeout.recv() => {
|
||||
//! println!("timed out, no message received in 5 seconds");
|
||||
//! break;
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user