diff options
| author | Steve Klabnik <steve@steveklabnik.com> | 2015-04-08 11:34:12 -0400 |
|---|---|---|
| committer | Steve Klabnik <steve@steveklabnik.com> | 2015-04-08 11:34:12 -0400 |
| commit | 12e9d7ced01ddb4d293fceedbd20d232cf78a8ca (patch) | |
| tree | 7baf72123e48f577846d74ef4ba537df892a4e95 /src | |
| parent | 91798a89e55ca1e10d73a45d4d619d91ca2ceead (diff) | |
| parent | 0027253f188cb6986f4d1281a31bb01769178f7d (diff) | |
| download | rust-12e9d7ced01ddb4d293fceedbd20d232cf78a8ca.tar.gz rust-12e9d7ced01ddb4d293fceedbd20d232cf78a8ca.zip | |
Rollup merge of #24178 - steveklabnik:new_toc, r=nikomatsakis
Basically, the overall structure is this: * Getting Started - getting an environment up and running * Learn Rust - project-based learning the basics * Effective Rust - higher level concepts that lead to writing good rust * Syntax and Semantics - chunks of exactly what it sounds like * Nightly Rust - unstable stuff, a staging area for documenting features * Glossary - self-explanatory There's a number of weaknesses with the current TOC, but I'll just focus on the strengths of the new one: We start off with getting our environment set up. That's "getting started". Then, we basically present you with two choices: do you want to start small, with bits of syntax? Or do you want to dive in with projects? I'm guessing more people will choose the second, so that's the next part: "Learn Rust." I don't have any chapters here, but this would have an updated guessing game, a tutorial on building a little `wc` clone, and something else I haven't decided yet. Lots of options. But the idea is to just dive in and get your hands dirty. I'll heavily link to the 'syntax and semantics' sections that are relevant. Then, a section I'm calling 'Effective Rust'. it feels greedy to steal that title, so I'm hoping to give it another name. These are higher-level things than syntax that Rust programmers should know: error handling is a great example. Most of these are sort of 'how do I use the standard library together' kinds of things. This also contains informations about systems programming that those new to it might not know: the stack vs the heap, for example. Then, "Syntax and Semantics." This has one section for each bit of Rust. Small, focused, but explains _everything_. These are positioned to be almost entirely in-order, but heavily cross-link, so you can go out of order if you want to, but you can also use it as a reference. Next, "Nightly Rust," where documenting unstable things goes. If we want to get good feedback on new features, they'll need to be documented, but we don't want to taint the main docs, so that's what this is for. Finally, the glossary. Straightforward enough. -------------------------------- This is going to be a terrible PR to review, so I just did the TOC re-organization, with basically no editing. So it'll be a bit jumbled at first. But next steps are to go through and edit / revise / tweak / add stuff to get it in tip-top shape for 1.0!
Diffstat (limited to 'src')
48 files changed, 845 insertions, 1942 deletions
diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 11e62aff42f..d894e1c4725 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -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) +* [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) + * [Documentation](documentation.md) + * [Iterators](iterators.md) + * [Concurrency](concurrency.md) + * [Error Handling](error-handling.md) + * [FFI](ffi.md) + * [`Deref` coercions](deref-coercions.md) +* [Syntax and Semantics](syntax-and-semantics.md) * [Variable Bindings](variable-bindings.md) - * [If](if.md) + * [Primitive Types](primitive-types.md) * [Functions](functions.md) * [Comments](comments.md) - * [Compound Data Types](compound-data-types.md) + * [Structs](structs.md) + * [Mutability](mutability.md) + * [Method Syntax](method-syntax.md) + * [Enums](enums.md) + * [`if`](if.md) * [Match](match.md) - * [Looping](looping.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) - * [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md) -* [Intermediate Rust](intermediate.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) - * [Testing](testing.md) - * [Pointers](pointers.md) - * [Ownership](ownership.md) - * [More Strings](more-strings.md) - * [Patterns](patterns.md) - * [Method Syntax](method-syntax.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) - * [Closures](closures.md) - * [Iterators](iterators.md) - * [Generics](generics.md) - * [Traits](traits.md) - * [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md) + * [Unsized Types](unsized-types.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) + * [`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) diff --git a/src/doc/trpl/advanced-macros.md b/src/doc/trpl/advanced-macros.md deleted file mode 100644 index fef458caaaf..00000000000 --- a/src/doc/trpl/advanced-macros.md +++ /dev/null @@ -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. diff --git a/src/doc/trpl/advanced.md b/src/doc/trpl/advanced.md deleted file mode 100644 index 447a8a614bf..00000000000 --- a/src/doc/trpl/advanced.md +++ /dev/null @@ -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! diff --git a/src/doc/trpl/arrays-vectors-and-slices.md b/src/doc/trpl/arrays-vectors-and-slices.md deleted file mode 100644 index 2916dca2c06..00000000000 --- a/src/doc/trpl/arrays-vectors-and-slices.md +++ /dev/null @@ -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. diff --git a/src/doc/trpl/arrays.md b/src/doc/trpl/arrays.md new file mode 100644 index 00000000000..a6ecac962d6 --- /dev/null +++ b/src/doc/trpl/arrays.md @@ -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. diff --git a/src/doc/trpl/attributes.md b/src/doc/trpl/attributes.md new file mode 100644 index 00000000000..e699bd85f6e --- /dev/null +++ b/src/doc/trpl/attributes.md @@ -0,0 +1,3 @@ +% Attributes + +Coming Soon! diff --git a/src/doc/trpl/basic.md b/src/doc/trpl/basic.md deleted file mode 100644 index c267830e6e0..00000000000 --- a/src/doc/trpl/basic.md +++ /dev/null @@ -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. diff --git a/src/doc/trpl/casting-between-types.md b/src/doc/trpl/casting-between-types.md new file mode 100644 index 00000000000..8bb0ec6db02 --- /dev/null +++ b/src/doc/trpl/casting-between-types.md @@ -0,0 +1,3 @@ +% Casting Between Types + +Coming Soon diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/compiler-plugins.md index 9eb22a7f698..9eb22a7f698 100644 --- a/src/doc/trpl/plugins.md +++ b/src/doc/trpl/compiler-plugins.md diff --git a/src/doc/trpl/compound-data-types.md b/src/doc/trpl/compound-data-types.md deleted file mode 100644 index e44d2edd667..00000000000 --- a/src/doc/trpl/compound-data-types.md +++ /dev/null @@ -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 diff --git a/src/doc/trpl/conclusion.md b/src/doc/trpl/conclusion.md deleted file mode 100644 index 9afddb11314..00000000000 --- a/src/doc/trpl/conclusion.md +++ /dev/null @@ -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! diff --git a/src/doc/trpl/conditional-compilation.md b/src/doc/trpl/conditional-compilation.md new file mode 100644 index 00000000000..40367fa844d --- /dev/null +++ b/src/doc/trpl/conditional-compilation.md @@ -0,0 +1,3 @@ +% Conditional Compilation + +Coming Soon! diff --git a/src/doc/trpl/const.md b/src/doc/trpl/const.md new file mode 100644 index 00000000000..9234c4fc2f9 --- /dev/null +++ b/src/doc/trpl/const.md @@ -0,0 +1,3 @@ +% `const` + +Coming soon! diff --git a/src/doc/trpl/debug-and-display.md b/src/doc/trpl/debug-and-display.md new file mode 100644 index 00000000000..6c8d788b5ae --- /dev/null +++ b/src/doc/trpl/debug-and-display.md @@ -0,0 +1,3 @@ +% `Debug` and `Display` + +Coming soon! diff --git a/src/doc/trpl/deref-coercions.md b/src/doc/trpl/deref-coercions.md new file mode 100644 index 00000000000..afacd304055 --- /dev/null +++ b/src/doc/trpl/deref-coercions.md @@ -0,0 +1,3 @@ +% `Deref` coercions + +Coming soon! diff --git a/src/doc/trpl/drop.md b/src/doc/trpl/drop.md new file mode 100644 index 00000000000..af58e23561c --- /dev/null +++ b/src/doc/trpl/drop.md @@ -0,0 +1,3 @@ +% `Drop` + +Coming soon! diff --git a/src/doc/trpl/effective-rust.md b/src/doc/trpl/effective-rust.md new file mode 100644 index 00000000000..6ea0759e99d --- /dev/null +++ b/src/doc/trpl/effective-rust.md @@ -0,0 +1 @@ +% Effective Rust diff --git a/src/doc/trpl/enums.md b/src/doc/trpl/enums.md new file mode 100644 index 00000000000..cbb74d97c35 --- /dev/null +++ b/src/doc/trpl/enums.md @@ -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 diff --git a/src/doc/trpl/for-loops.md b/src/doc/trpl/for-loops.md new file mode 100644 index 00000000000..45ae5a2e2dd --- /dev/null +++ b/src/doc/trpl/for-loops.md @@ -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. diff --git a/src/doc/trpl/getting-started.md b/src/doc/trpl/getting-started.md new file mode 100644 index 00000000000..a164def516b --- /dev/null +++ b/src/doc/trpl/getting-started.md @@ -0,0 +1 @@ +% Getting Started diff --git a/src/doc/trpl/if.md b/src/doc/trpl/if.md index 7dac49987d8..92f95341f81 100644 --- a/src/doc/trpl/if.md +++ b/src/doc/trpl/if.md @@ -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` diff --git a/src/doc/trpl/intermediate.md b/src/doc/trpl/intermediate.md deleted file mode 100644 index 73370a32231..00000000000 --- a/src/doc/trpl/intermediate.md +++ /dev/null @@ -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. diff --git a/src/doc/trpl/learn-rust.md b/src/doc/trpl/learn-rust.md new file mode 100644 index 00000000000..e5482d3fb96 --- /dev/null +++ b/src/doc/trpl/learn-rust.md @@ -0,0 +1 @@ +% Learn Rust diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md new file mode 100644 index 00000000000..c6eee97dc6a --- /dev/null +++ b/src/doc/trpl/lifetimes.md @@ -0,0 +1,3 @@ +% Lifetimes + +Coming soon! diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md index 7e19ec94ee7..6d21cb59383 100644 --- a/src/doc/trpl/macros.md +++ b/src/doc/trpl/macros.md @@ -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. diff --git a/src/doc/trpl/more-strings.md b/src/doc/trpl/more-strings.md deleted file mode 100644 index 17a463842e7..00000000000 --- a/src/doc/trpl/more-strings.md +++ /dev/null @@ -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); -``` diff --git a/src/doc/trpl/move-semantics.md b/src/doc/trpl/move-semantics.md new file mode 100644 index 00000000000..6917d7f8b8e --- /dev/null +++ b/src/doc/trpl/move-semantics.md @@ -0,0 +1,3 @@ +% Move Semantics + +Coming Soon diff --git a/src/doc/trpl/mutability.md b/src/doc/trpl/mutability.md new file mode 100644 index 00000000000..ccb03c7f85f --- /dev/null +++ b/src/doc/trpl/mutability.md @@ -0,0 +1,3 @@ +% Mutability + +Coming Soon diff --git a/src/doc/trpl/unstable.md b/src/doc/trpl/nightly-rust.md index d69831c2378..1b58b73994d 100644 --- a/src/doc/trpl/unstable.md +++ b/src/doc/trpl/nightly-rust.md @@ -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 diff --git a/src/doc/trpl/operators-and-overloading.md b/src/doc/trpl/operators-and-overloading.md new file mode 100644 index 00000000000..f6f9d5cae19 --- /dev/null +++ b/src/doc/trpl/operators-and-overloading.md @@ -0,0 +1,3 @@ +% Operators and Overloading + +Coming soon! diff --git a/src/doc/trpl/pointers.md b/src/doc/trpl/pointers.md deleted file mode 100644 index 1b3f2a5b773..00000000000 --- a/src/doc/trpl/pointers.md +++ /dev/null @@ -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 diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md new file mode 100644 index 00000000000..2878e7ce475 --- /dev/null +++ b/src/doc/trpl/primitive-types.md @@ -0,0 +1,3 @@ +% Primitive Types + +Coming Soon! diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md new file mode 100644 index 00000000000..6acb326958d --- /dev/null +++ b/src/doc/trpl/references-and-borrowing.md @@ -0,0 +1,3 @@ +% References and Borrowing + +Coming Soon! diff --git a/src/doc/trpl/slices.md b/src/doc/trpl/slices.md new file mode 100644 index 00000000000..a31c0ac3c4e --- /dev/null +++ b/src/doc/trpl/slices.md @@ -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. diff --git a/src/doc/trpl/static.md b/src/doc/trpl/static.md new file mode 100644 index 00000000000..b29c4952c94 --- /dev/null +++ b/src/doc/trpl/static.md @@ -0,0 +1,3 @@ +% `static` + +Coming soon! diff --git a/src/doc/trpl/structs.md b/src/doc/trpl/structs.md new file mode 100644 index 00000000000..eff1a47761d --- /dev/null +++ b/src/doc/trpl/structs.md @@ -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)`. diff --git a/src/doc/trpl/syntax-and-semantics.md b/src/doc/trpl/syntax-and-semantics.md new file mode 100644 index 00000000000..6f992cf6887 --- /dev/null +++ b/src/doc/trpl/syntax-and-semantics.md @@ -0,0 +1 @@ +% Syntax and Semantics diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md new file mode 100644 index 00000000000..cc0941bc025 --- /dev/null +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -0,0 +1,3 @@ +% The Stack and the Heap + +Coming Soon diff --git a/src/doc/trpl/tracing-macros.md b/src/doc/trpl/tracing-macros.md deleted file mode 100644 index 6226ea9f3e7..00000000000 --- a/src/doc/trpl/tracing-macros.md +++ /dev/null @@ -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. diff --git a/src/doc/trpl/static-and-dynamic-dispatch.md b/src/doc/trpl/trait-objects.md index a7794814156..d008d30597f 100644 --- a/src/doc/trpl/static-and-dynamic-dispatch.md +++ b/src/doc/trpl/trait-objects.md @@ -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 diff --git a/src/doc/trpl/tuple-structs.md b/src/doc/trpl/tuple-structs.md new file mode 100644 index 00000000000..8fba658fba2 --- /dev/null +++ b/src/doc/trpl/tuple-structs.md @@ -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`. diff --git a/src/doc/trpl/tuples.md b/src/doc/trpl/tuples.md new file mode 100644 index 00000000000..dd526d05b67 --- /dev/null +++ b/src/doc/trpl/tuples.md @@ -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. diff --git a/src/doc/trpl/type-aliases.md b/src/doc/trpl/type-aliases.md new file mode 100644 index 00000000000..fffa0ae1383 --- /dev/null +++ b/src/doc/trpl/type-aliases.md @@ -0,0 +1,3 @@ +% `type` Aliases + +Coming soon diff --git a/src/doc/trpl/ufcs.md b/src/doc/trpl/ufcs.md new file mode 100644 index 00000000000..6b9a417c439 --- /dev/null +++ b/src/doc/trpl/ufcs.md @@ -0,0 +1,3 @@ +% Universal Function Call Syntax + +Coming soon diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe-code.md index 3ca3cfd0588..b641f2b104a 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe-code.md @@ -1,4 +1,4 @@ -% Unsafe and Low-Level Code +% Unsafe Code # Introduction diff --git a/src/doc/trpl/unsized-types.md b/src/doc/trpl/unsized-types.md new file mode 100644 index 00000000000..f307f23f011 --- /dev/null +++ b/src/doc/trpl/unsized-types.md @@ -0,0 +1,3 @@ +% Unsized Types + +Coming Soon! diff --git a/src/doc/trpl/vectors.md b/src/doc/trpl/vectors.md new file mode 100644 index 00000000000..cba435233fa --- /dev/null +++ b/src/doc/trpl/vectors.md @@ -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. diff --git a/src/doc/trpl/looping.md b/src/doc/trpl/while-loops.md index 28f02b1ffe1..508c4ee117a 100644 --- a/src/doc/trpl/looping.md +++ b/src/doc/trpl/while-loops.md @@ -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: |
