From 1db3df8878cd75104223ec5f1e0ac41496d7d862 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Fri, 17 Apr 2015 05:05:22 -0700 Subject: [PATCH 01/23] Fix the dependency for the pretty-rpass-full tests The current code attempts to define the PRETTY_DEPS$(1)_H_$(3)_pretty-rpass-full variable, which does not work, because $(1) and $(3) are not inside a function. Moving it into a function helps, but we need the target library (TLIB), not the host library (HLIB). Moreover, there is a test (run-pass-fulldeps/compiler-calls.rs) that uses rustc_driver, which is not an indirect dependency of librustc or libsyntax. Listing all the dependencies will be hard to maintain, but there's a better way to do this... As with the rpass-full and cfail-full tests, add dependencies using the $$(CSREQ$(1)_T_$(2)_H_$(3)) variable, which includes the complete set of host and target crates, built for a particular stage, host, and target. Fixes #22021 --- mk/tests.mk | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index a540d2bace4c6..6a49a7c659fb9 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -753,13 +753,6 @@ PRETTY_DEPS_pretty-rpass-full = $(RPASS_FULL_TESTS) PRETTY_DEPS_pretty-rfail = $(RFAIL_TESTS) PRETTY_DEPS_pretty-bench = $(BENCH_TESTS) PRETTY_DEPS_pretty-pretty = $(PRETTY_TESTS) -# The stage- and host-specific dependencies are for e.g. macro_crate_test which pulls in -# external crates. -PRETTY_DEPS$(1)_H_$(3)_pretty-rpass = -PRETTY_DEPS$(1)_H_$(3)_pretty-rpass-full = $$(HLIB$(1)_H_$(3))/stamp.syntax $$(HLIB$(1)_H_$(3))/stamp.rustc -PRETTY_DEPS$(1)_H_$(3)_pretty-rfail = -PRETTY_DEPS$(1)_H_$(3)_pretty-bench = -PRETTY_DEPS$(1)_H_$(3)_pretty-pretty = PRETTY_DIRNAME_pretty-rpass = run-pass PRETTY_DIRNAME_pretty-rpass-valgrind = run-pass-valgrind PRETTY_DIRNAME_pretty-rpass-full = run-pass-fulldeps @@ -767,6 +760,15 @@ PRETTY_DIRNAME_pretty-rfail = run-fail PRETTY_DIRNAME_pretty-bench = bench PRETTY_DIRNAME_pretty-pretty = pretty +define DEF_PRETTY_FULLDEPS +PRETTY_DEPS$(1)_T_$(2)_H_$(3)_pretty-rpass-full = $$(CSREQ$(1)_T_$(2)_H_$(3)) +endef + +$(foreach host,$(CFG_HOST), \ + $(foreach target,$(CFG_TARGET), \ + $(foreach stage,$(STAGES), \ + $(eval $(call DEF_PRETTY_FULLDEPS,$(stage),$(target),$(host)))))) + define DEF_RUN_PRETTY_TEST PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4) := \ @@ -780,7 +782,7 @@ check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4 $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ $$(PRETTY_DEPS_$(4)) \ - $$(PRETTY_DEPS$(1)_H_$(3)_$(4)) + $$(PRETTY_DEPS$(1)_T_$(2)_H_$(3)_$(4)) @$$(call E, run pretty-rpass [$(2)]: $$<) $$(Q)touch $$@.start_time $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ From 566d6531fca08a9645dfef6c9ea96477d87a461c Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Fri, 17 Apr 2015 04:58:47 -0700 Subject: [PATCH 02/23] Fix run-make/simd-ffi to work with parallel make check. --- src/test/run-make/simd-ffi/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/run-make/simd-ffi/Makefile b/src/test/run-make/simd-ffi/Makefile index 68a6a5fbfe864..dc0fcec1980fd 100644 --- a/src/test/run-make/simd-ffi/Makefile +++ b/src/test/run-make/simd-ffi/Makefile @@ -27,7 +27,8 @@ define MK_TARGETS # on some platforms, but LLVM just prints a warning so that's fine for # now. $(1): simd.rs - $$(RUSTC) --target=$(1) --emit=llvm-ir,asm simd.rs -C target-feature='+neon,+sse2' + $$(RUSTC) --target=$(1) --emit=llvm-ir,asm simd.rs \ + -C target-feature='+neon,+sse2' -C extra-filename=-$(1) endef $(foreach targetxxx,$(TARGETS),$(eval $(call MK_TARGETS,$(targetxxx)))) From be08d35c8f7ad93912e2aae794c79e4ab75f9c0f Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 20 Apr 2015 08:57:06 -0400 Subject: [PATCH 03/23] Simplify alloc::arc::Arc example in doc-comment As far as I can tell, this conversion to integer to floating point does not need to happen and is beside the point --- src/liballoc/arc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 0cfdcd2413fd9..3afc34be2cac8 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -103,7 +103,7 @@ use heap::deallocate; /// use std::thread; /// /// fn main() { -/// let numbers: Vec<_> = (0..100u32).map(|i| i as f32).collect(); +/// let numbers: Vec<_> = (0..100u32).collect(); /// let shared_numbers = Arc::new(numbers); /// /// for _ in 0..10 { From 213708867ed1ed26f748de9a9c955dc64ba0e1ae Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 15:29:13 -0400 Subject: [PATCH 04/23] TRPL editing: enums Now that we're not doing the guessing game, a lot of this is irrelevant. --- src/doc/trpl/enums.md | 129 ++++++++---------------------------------- 1 file changed, 25 insertions(+), 104 deletions(-) diff --git a/src/doc/trpl/enums.md b/src/doc/trpl/enums.md index 504bd099171ba..80ea25eb35ce9 100644 --- a/src/doc/trpl/enums.md +++ b/src/doc/trpl/enums.md @@ -1,11 +1,9 @@ % 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 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. ```rust enum Character { @@ -14,14 +12,14 @@ enum Character { } ``` -Most normal types are allowed as the variant components of an `enum`. Here are -some examples: +Most 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 Stats { Health: i32, Mana: i32, Attack: i32, Defense: i32 } struct HeightDatabase(Vec); ``` @@ -30,12 +28,12 @@ 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: +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} +```rust,ignore // These assignments both succeed let ten = Character::Digit(10); let four = Character::Digit(4); @@ -50,98 +48,21 @@ let four_is_smaller = four <= ten; 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: +We use the `::` syntax to use the name of each variant: They’re scoped by the name +of the `enum` itself. This allows both of these to work: -``` -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"); } -} +```rust,ignore +Character::Digit(10); +Hand::Digit; ``` -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. +Both variants are named `Digit`, but since they’re scoped to the `enum` name, -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. +Not supporting these operations 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 section. We don’t know enough about Rust to implement +equality yet, but we’ll find out in the [`traits`][traits] section. -[match]: ./match.html -[generics]: ./generics.html +[match]: match.html +[traits]: traits.html From 836c8a826b6b21dd38bbef9d4988e90a1cc0e852 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 15:32:26 -0400 Subject: [PATCH 05/23] TRPL editing: match --- src/doc/trpl/match.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/doc/trpl/match.md b/src/doc/trpl/match.md index 33d603f326af3..2c0c8ea73c03c 100644 --- a/src/doc/trpl/match.md +++ b/src/doc/trpl/match.md @@ -1,10 +1,8 @@ % Match -Often, a simple `if`/`else` isn’t enough, because you have more than two -possible options. Also, `else` conditions can get incredibly complicated, so -what’s the solution? - -Rust has a keyword, `match`, that allows you to replace complicated `if`/`else` +Often, a simple [`if`][if]/`else` isn’t enough, because you have more than two +possible options. Also, conditions can get quite complex. Rust +has a keyword, `match`, that allows you to replace complicated `if`/`else` groupings with something more powerful. Check it out: ```rust @@ -20,16 +18,18 @@ match x { } ``` -`match` takes an expression and then branches based on its value. Each *arm* of +[if]: if.html + +`match` takes an expression and then branches based on its value. Each ‘arm’ of the branch is of the form `val => expression`. When the value matches, that arm’s expression will be evaluated. It’s called `match` because of the term ‘pattern matching’, which `match` is an implementation of. There’s an [entire section on -patterns][patterns] coming up next, that covers all the options that fit here. +patterns][patterns] that covers all the patterns that are possible here. [patterns]: patterns.html -So what’s the big advantage here? Well, there are a few. First of all, `match` -enforces *exhaustiveness checking*. Do you see that last arm, the one with the +So what’s the big advantage? Well, there are a few. First of all, `match` +enforces ‘exhaustiveness checking’. Do you see that last arm, the one with the underscore (`_`)? If we remove that arm, Rust will give us an error: ```text @@ -37,11 +37,12 @@ error: non-exhaustive patterns: `_` not covered ``` In other words, Rust is trying to tell us we forgot a value. Because `x` is an -integer, Rust knows that it can have a number of different values – for example, -`6`. Without the `_`, however, there is no arm that could match, and so Rust refuses -to compile. `_` acts like a ‘catch-all arm’. If none of the other arms match, -the arm with `_` will, and since we have this catch-all arm, we now have an arm -for every possible value of `x`, and so our program will compile successfully. +integer, Rust knows that it can have a number of different values – for +example, `6`. Without the `_`, however, there is no arm that could match, and +so Rust refuses to compile the code. `_` acts like a ‘catch-all arm’. If none +of the other arms match, the arm with `_` will, and since we have this +catch-all arm, we now have an arm for every possible value of `x`, and so our +program will compile successfully. `match` is also an expression, which means we can use it on the right-hand side of a `let` binding or directly where an expression is used: @@ -59,4 +60,4 @@ let numer = match x { }; ``` -Sometimes, it’s a nice way of converting things. +Sometimes it’s a nice way of converting something from one type to another. From 9661efac8bd811abfb032c73c1dcdc90cd761dd8 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 15:52:29 -0400 Subject: [PATCH 06/23] TRPL editing: patterns Partially addresses #24388 --- src/doc/trpl/patterns.md | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/doc/trpl/patterns.md b/src/doc/trpl/patterns.md index c88e3a0f9edf5..97a3dfe8a7640 100644 --- a/src/doc/trpl/patterns.md +++ b/src/doc/trpl/patterns.md @@ -21,6 +21,8 @@ match x { } ``` +This prints `one`. + # Multiple patterns You can match multiple patterns with `|`: @@ -35,6 +37,8 @@ match x { } ``` +This prints `one or two`. + # Ranges You can match a range of values with `...`: @@ -48,7 +52,21 @@ match x { } ``` -Ranges are mostly used with integers and single characters. +This prints `one through five`. + +Ranges are mostly used with integers and `char`s: + +```rust +let x = '💅'; + +match x { + 'a' ... 'j' => println!("early letter"), + 'k' ... 'z' => println!("late letter"), + _ => println!("something else"), +} +``` + +This prints `something else` # Bindings @@ -64,6 +82,8 @@ match x { } ``` +This prints `got a range element 1`. + # Ignoring variants If you’re matching on an enum which has variants, you can use `..` to @@ -83,6 +103,8 @@ match x { } ``` +This prints `Got an int!`. + # Guards You can introduce ‘match guards’ with `if`: @@ -102,6 +124,8 @@ match x { } ``` +This prints `Got an int!` + # ref and ref mut If you want to get a [reference][ref], use the `ref` keyword: @@ -114,6 +138,8 @@ match x { } ``` +This prints `Got a reference to 5`. + [ref]: references-and-borrowing.html Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref` @@ -130,7 +156,7 @@ match x { # Destructuring -If you have a compound data type, like a `struct`, you can destructure it +If you have a compound data type, like a [`struct`][struct], you can destructure it inside of a pattern: ```rust @@ -146,6 +172,8 @@ match origin { } ``` +[struct]: structs.html + If we only care about some of the values, we don’t have to give them all names: ```rust @@ -161,6 +189,8 @@ match origin { } ``` +This prints `x is 0`. + You can do this kind of match on any member, not just the first: ```rust @@ -176,6 +206,8 @@ match origin { } ``` +This prints `y is 0`. + This ‘destructuring’ behavior works on any compound data type, like [tuples][tuples] or [enums][enums]. @@ -187,10 +219,10 @@ This ‘destructuring’ behavior works on any compound data type, like Whew! That’s a lot of different ways to match things, and they can all be mixed and matched, depending on what you’re doing: -```{rust,ignore} +```rust,ignore match x { Foo { x: Some(ref name), y: None } => ... } ``` -Patterns are very powerful. Make good use of them. +Patterns are very powerful. Make good use of them. From 44db46a308733a6c02c38a02891ea80a89e7b7c0 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 15:52:44 -0400 Subject: [PATCH 07/23] TRPL editing: move patterns back We want to talk about how to pattern match on structs, so let's bump it back one. --- src/doc/trpl/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index f2d1666048d89..8b73881f2f12f 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -30,8 +30,8 @@ * [Move semantics](move-semantics.md) * [Enums](enums.md) * [Match](match.md) - * [Patterns](patterns.md) * [Structs](structs.md) + * [Patterns](patterns.md) * [Method Syntax](method-syntax.md) * [Drop](drop.md) * [Vectors](vectors.md) From 7f43c5782cb252ba800d44a17b5c184aedffb6c7 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 15:54:33 -0400 Subject: [PATCH 08/23] TRPL editing: structs --- src/doc/trpl/structs.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/trpl/structs.md b/src/doc/trpl/structs.md index 83d5a15bc2c0a..ff249d6043c10 100644 --- a/src/doc/trpl/structs.md +++ b/src/doc/trpl/structs.md @@ -1,6 +1,6 @@ % Structs -Structs are a way of creating more complex datatypes. For example, if we were +Structs are a way of creating more complex data types. For example, if we were doing calculations involving coordinates in 2D space, we would need both an `x` and a `y` value: @@ -24,12 +24,12 @@ fn main() { } ``` -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`. +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, `struct`s begin with +a capital letter and are 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 +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 From f81b1fcf8c9fccfb9c2465ee19317328e4dfe5b1 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 16:01:28 -0400 Subject: [PATCH 09/23] TRPL edits: method syntax --- src/doc/trpl/method-syntax.md | 71 +++++++++++++++++------------------ 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index ae83a930a187c..5853f3d679c5f 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -3,27 +3,26 @@ Functions are great, but if you want to call a bunch of them on some data, it can be awkward. Consider this code: -```{rust,ignore} +```rust,ignore baz(bar(foo))); ``` -We would read this left-to right, and so we see "baz bar foo." But this isn't the -order that the functions would get called in, that's inside-out: "foo bar baz." -Wouldn't it be nice if we could do this instead? +We would read this left-to right, and so we see ‘baz bar foo’. But this isn’t the +order that the functions would get called in, that’s inside-out: ‘foo bar baz’. +Wouldn’t it be nice if we could do this instead? -```{rust,ignore} +```rust,ignore foo.bar().baz(); ``` Luckily, as you may have guessed with the leading question, you can! Rust provides -the ability to use this *method call syntax* via the `impl` keyword. +the ability to use this ‘method call syntax’ via the `impl` keyword. ## Method calls -Here's how it works: +Here’s how it works: -```{rust} -# #![feature(core)] +```rust struct Circle { x: f64, y: f64, @@ -44,15 +43,23 @@ fn main() { This will print `12.566371`. -We've made a struct that represents a circle. We then write an `impl` block, -and inside it, define a method, `area`. Methods take a special first -parameter, of which there are three variants: `self`, `&self`, and `&mut self`. -You can think of this first parameter as being the `foo` in `foo.bar()`. The three -variants correspond to the three kinds of things `foo` could be: `self` if it's -just a value on the stack, `&self` if it's a reference, and `&mut self` if it's -a mutable reference. We should default to using `&self`, as you should prefer -borrowing over taking ownership, as well as taking immutable references -over mutable ones. Here's an example of all three variants: + + +We’ve made a struct that represents a circle. We then write an `impl` block, +and inside it, define a method, `area`. + +Methods take a special first parameter, of which there are three variants: +`self`, `&self`, and `&mut self`. You can think of this first parameter as +being the `foo` in `foo.bar()`. The three variants correspond to the three +kinds of things `foo` could be: `self` if it’s just a value on the stack, +`&self` if it’s a reference, and `&mut self` if it’s a mutable reference. +Because we took the `&self` parameter to `area`, we can use it just like any +other parameter. Because we know it’s a `Circle`, we can access the `radius` +just like we would with any other struct. + +We should default to using `&self`, as you should prefer borrowing over taking +ownership, as well as taking immutable references over mutable ones. Here’s an +example of all three variants: ```rust struct Circle { @@ -76,20 +83,13 @@ impl Circle { } ``` -Finally, as you may remember, the value of the area of a circle is `π*r²`. -Because we took the `&self` parameter to `area`, we can use it just like any -other parameter. Because we know it's a `Circle`, we can access the `radius` -just like we would with any other struct. An import of π and some -multiplications later, and we have our area. - ## Chaining method calls So, now we know how to call a method, such as `foo.bar()`. But what about our -original example, `foo.bar().baz()`? This is called 'method chaining', and we +original example, `foo.bar().baz()`? This is called ‘method chaining’, and we can do it by returning `self`. ``` -# #![feature(core)] struct Circle { x: f64, y: f64, @@ -124,13 +124,13 @@ fn grow(&self) -> Circle { # Circle } } ``` -We just say we're returning a `Circle`. With this method, we can grow a new +We just say we’re returning a `Circle`. With this method, we can grow a new circle to any arbitrary size. ## Static methods -You can also define methods that do not take a `self` parameter. Here's a -pattern that's very common in Rust code: +You can also define methods that do not take a `self` parameter. Here’s a +pattern that’s very common in Rust code: ``` struct Circle { @@ -154,20 +154,19 @@ fn main() { } ``` -This *static method* builds a new `Circle` for us. Note that static methods +This ‘static method’ builds a new `Circle` for us. Note that static methods are called with the `Struct::method()` syntax, rather than the `ref.method()` syntax. ## Builder Pattern -Let's say that we want our users to be able to create Circles, but we will +Let’s say that we want our users to be able to create Circles, but we will allow them to only set the properties they care about. Otherwise, the `x` -and `y` attributes will be `0.0`, and the `radius` will be `1.0`. Rust doesn't +and `y` attributes will be `0.0`, and the `radius` will be `1.0`. Rust doesn’t have method overloading, named arguments, or variable arguments. We employ the builder pattern instead. It looks like this: ``` -# #![feature(core)] struct Circle { x: f64, y: f64, @@ -224,9 +223,9 @@ fn main() { } ``` -What we've done here is make another struct, `CircleBuilder`. We've defined our -builder methods on it. We've also defined our `area()` method on `Circle`. We +What we’ve done here is make another struct, `CircleBuilder`. We’ve defined our +builder methods on it. We’ve also defined our `area()` method on `Circle`. We also made one more method on `CircleBuilder`: `finalize()`. This method creates -our final `Circle` from the builder. Now, we've used the type system to enforce +our final `Circle` from the builder. Now, we’ve used the type system to enforce our concerns: we can use the methods on `CircleBuilder` to constrain making `Circle`s in any way we choose. From a3a2049166436e6cabfb73de42b91d6228eef184 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 16:02:45 -0400 Subject: [PATCH 10/23] Move drop back in TRPL TOC It's a trait implementation, so we need traits first. --- src/doc/trpl/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 8b73881f2f12f..33ee0cc49ed01 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -33,11 +33,11 @@ * [Structs](structs.md) * [Patterns](patterns.md) * [Method Syntax](method-syntax.md) - * [Drop](drop.md) * [Vectors](vectors.md) * [Strings](strings.md) * [Traits](traits.md) * [Operators and Overloading](operators-and-overloading.md) + * [Drop](drop.md) * [Generics](generics.md) * [if let](if-let.md) * [Trait Objects](trait-objects.md) From 73d3d6855042696c814e69570d03f70c3fd36409 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 16:20:56 -0400 Subject: [PATCH 11/23] TRPL editing: vectors --- src/doc/trpl/vectors.md | 63 +++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/src/doc/trpl/vectors.md b/src/doc/trpl/vectors.md index 6fa5917ea99ba..965cb218c699a 100644 --- a/src/doc/trpl/vectors.md +++ b/src/doc/trpl/vectors.md @@ -1,37 +1,58 @@ % Vectors -A *vector* is a dynamic or "growable" array, implemented as the standard -library type [`Vec`](../std/vec/) (Where `` is a [Generic](./generics.md) -statement). Vectors always allocate their data on the heap. Vectors are to -[slices][slices] what [`String`][string] is to `&str`. You can -create them with the `vec!` macro: - -```{rust} -let v = vec![1, 2, 3]; // v: Vec -``` +A ‘vector’ is a dynamic or ‘growable’ array, implemented as the standard +library type [`Vec`][vec]. That `` is a [generic][generic], meaning we +can have vectors of any type. Vectors always allocate their data on the heap. +You can create them with the `vec!` macro: -[slices]: primitive-types.html#slices -[string]: strings.html +```rust +let v = vec![1, 2, 3, 4, 5]; // v: Vec +``` -(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, +(Notice that unlike the `println!` macro we’ve used in the past, we use square +brackets `[]` with `vec!` macro. 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: +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: +## Accessing elements -```{rust} -let mut nums = vec![1, 2, 3]; // mut nums: Vec +To get the value at a particular index in the vector, we use `[]`s: -nums.push(4); +```rust +let v = vec![1, 2, 3, 4, 5]; -println!("The length of nums is now {}", nums.len()); // Prints 4 +println!("The third element of v is {}", v[2]); ``` -Vectors have many more useful methods. +The indices count from `0`, so the third element is `v[2]`. + +## Iterating + +Once you have a vector, you can iterate through its elements with `for`. There +are three versions: + +```rust +let mut v = vec![1, 2, 3, 4, 5]; + +for i in &v { + println!("A reference to {}", i); +} + +for i in &mut v { + println!("A mutable reference to {}", i); +} + +for i in v { + println!("Take ownership of the vector and its element {}", i); +} +``` + +Vectors have many more useful methods, which you can read about in [their +API documentation][vec]. + +[vec]: ../std/vec/index.html From 5b54a4f03b9a8d40128e990b17f74b0d40c5f321 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 16:54:27 -0400 Subject: [PATCH 12/23] TRPL copyedits: strings --- src/doc/trpl/strings.md | 114 ++++++++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 23 deletions(-) diff --git a/src/doc/trpl/strings.md b/src/doc/trpl/strings.md index 2c2e6a8c7c5ac..6ed4c7cb1b379 100644 --- a/src/doc/trpl/strings.md +++ b/src/doc/trpl/strings.md @@ -1,36 +1,34 @@ % Strings -Strings are an important concept for any programmer to master. Rust's string +Strings are an important concept for any programmer to master. Rust’s string handling system is a bit different from other languages, due to its systems focus. Any time you have a data structure of variable size, things can get -tricky, and strings are a re-sizable data structure. That being said, Rust's +tricky, and strings are a re-sizable data structure. That being said, Rust’s strings also work differently than in some other systems languages, such as C. -Let's dig into the details. 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. +Let’s dig into the details. A ‘string’ is a sequence of Unicode scalar values +encoded as a stream of UTF-8 bytes. All strings are guaranteed to be a valid +encoding of UTF-8 sequences. Additionally, unlike some systems languages, +strings are not null-terminated and can contain null bytes. -Rust has two main types of strings: `&str` and `String`. +Rust has two main types of strings: `&str` and `String`. Let’s talk about +`&str` first. These are called ‘string slices’. String literals are of the type +`&'static str`: -The first kind is a `&str`. These are called *string slices*. String literals -are of the type `&str`: - -```{rust} -let string = "Hello there."; // string: &str +```rust +let string = "Hello there."; // string: &'static str ``` -This string is statically allocated, meaning that it's saved inside our +This string is statically allocated, meaning that it’s saved inside our compiled program, and exists for the entire duration it runs. The `string` binding is a reference to this statically allocated string. String slices have a fixed size, and cannot be mutated. -A `String`, on the other hand, 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. +A `String`, on the other hand, 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. -```{rust} +```rust let mut s = "Hello".to_string(); // mut s: String println!("{}", s); @@ -54,8 +52,78 @@ fn main() { Viewing a `String` as a `&str` is cheap, but converting the `&str` to a `String` involves allocating memory. No reason to do that unless you have to! -That's the basics of strings in Rust! They're probably a bit more complicated -than you are used to, if you come from a scripting language, but when the -low-level details matter, they really matter. Just remember that `String`s -allocate memory and control their data, while `&str`s are a reference to -another string, and you'll be all set. +## Indexing + +Because strings are valid UTF-8, strings do not support indexing: + +```rust,ignore +let s = "hello"; + +println!("The first letter of s is {}", s[0]); // ERROR!!! +``` + +Usually, access to a vector with `[]` is very fast. But, because each character +in a UTF-8 encoded string can be multiple bytes, you have to walk over the +string to find the nᵗʰ letter of a string. This is a significantly more +expensive operation, and we don’t want to be misleading. Furthermore, ‘letter’ +isn’t something defined in Unicode, exactly. We can choose to look at a string as +individual bytes, or as codepoints: + +```rust +let hachiko = "忠犬ハチ公"; + +for b in hachiko.as_bytes() { +print!("{}, ", b); +} + +println!(""); + +for c in hachiko.chars() { +print!("{}, ", c); +} + +println!(""); +``` + +This prints: + +```text +229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172, +忠, 犬, ハ, チ, 公, +``` + +As you can see, there are more bytes than `char`s. + +You can get something similar to an index like this: + +```rust +# let hachiko = "忠犬ハチ公"; +let dog = hachiko.chars().nth(1); // kinda like hachiko[1] +``` + +This emphasizes that we have to go through the whole list of `chars`. + +## Concatenation + +If you have a `String`, you can concatenate a `&str` to the end of it: + +```rust +let hello = "Hello ".to_string(); +let world = "world!"; + +let hello_world = hello + world; +``` + +But if you have two `String`s, you need an `&`: + +```rust +let hello = "Hello ".to_string(); +let world = "world!".to_string(); + +let hello_world = hello + &world; +``` + +This is because `&String` can automatically coerece to a `&str`. This is a +feature called ‘[`Deref` coercions][dc]’. + +[dc]: deref-coercions.html From 1646ebd5baae3bc2eea9ace51c3b9bf497dad80e Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 16:56:49 -0400 Subject: [PATCH 13/23] move Deref coercions to syntax and semantics It's a language feature, so it belongs here. --- src/doc/trpl/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 33ee0cc49ed01..1e01697c1e705 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -14,7 +14,6 @@ * [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) * [Functions](functions.md) @@ -53,6 +52,7 @@ * [Casting between types](casting-between-types.md) * [Associated Types](associated-types.md) * [Unsized Types](unsized-types.md) + * [Deref coercions](deref-coercions.md) * [Macros](macros.md) * [`unsafe` Code](unsafe-code.md) * [Nightly Rust](nightly-rust.md) From e289b689d4c1af7da5f665321942713cdc3be95d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 17:21:26 -0400 Subject: [PATCH 14/23] TRPL edits: traits Let's talk about generics first, since we use traits to bound them in funtions. Partially addresses #24325 Fixes #24271 --- src/doc/trpl/SUMMARY.md | 2 +- src/doc/trpl/traits.md | 288 ++++++++++++++-------------------------- 2 files changed, 101 insertions(+), 189 deletions(-) diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 1e01697c1e705..ec886899e6fe9 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -34,10 +34,10 @@ * [Method Syntax](method-syntax.md) * [Vectors](vectors.md) * [Strings](strings.md) + * [Generics](generics.md) * [Traits](traits.md) * [Operators and Overloading](operators-and-overloading.md) * [Drop](drop.md) - * [Generics](generics.md) * [if let](if-let.md) * [Trait Objects](trait-objects.md) * [Closures](closures.md) diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index 25f5c7cacc771..7330e42ccf689 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -1,10 +1,9 @@ % Traits -Do you remember the `impl` keyword, used to call a function with method -syntax? +Do you remember the `impl` keyword, used to call a function with [method +syntax][methodsyntax]? -```{rust} -# #![feature(core)] +```rust struct Circle { x: f64, y: f64, @@ -18,11 +17,12 @@ impl Circle { } ``` +[methodsyntax]: method-syntax.html + Traits are similar, except that we define a trait with just the method signature, then implement the trait for that struct. Like this: -```{rust} -# #![feature(core)] +```rust struct Circle { x: f64, y: f64, @@ -41,20 +41,13 @@ impl HasArea for Circle { ``` As you can see, the `trait` block looks very similar to the `impl` block, -but we don't define a body, just a type signature. When we `impl` a trait, +but we don’t define a body, just a type signature. When we `impl` a trait, we use `impl Trait for Item`, rather than just `impl Item`. -So what's the big deal? Remember the error we were getting with our generic -`inverse` function? - -```text -error: binary operation `==` cannot be applied to type `T` -``` - We can use traits to constrain our generics. Consider this function, which does not compile, and gives us a similar error: -```{rust,ignore} +```rust,ignore fn print_area(shape: T) { println!("This shape has an area of {}", shape.area()); } @@ -66,11 +59,11 @@ Rust complains: error: type `T` does not implement any method in scope named `area` ``` -Because `T` can be any type, we can't be sure that it implements the `area` -method. But we can add a *trait constraint* to our generic `T`, ensuring +Because `T` can be any type, we can’t be sure that it implements the `area` +method. But we can add a ‘trait constraint’ to our generic `T`, ensuring that it does: -```{rust} +```rust # trait HasArea { # fn area(&self) -> f64; # } @@ -83,10 +76,9 @@ The syntax `` means `any type that implements the HasArea trait`. Because traits define function type signatures, we can be sure that any type which implements `HasArea` will have an `.area()` method. -Here's an extended example of how this works: +Here’s an extended example of how this works: -```{rust} -# #![feature(core)] +```rust trait HasArea { fn area(&self) -> f64; } @@ -144,10 +136,10 @@ This shape has an area of 3.141593 This shape has an area of 1 ``` -As you can see, `print_area` is now generic, but also ensures that we -have passed in the correct types. If we pass in an incorrect type: +As you can see, `print_area` is now generic, but also ensures that we have +passed in the correct types. If we pass in an incorrect type: -```{rust,ignore} +```rust,ignore print_area(5); ``` @@ -157,11 +149,11 @@ We get a compile-time error: error: failed to find an implementation of trait main::HasArea for int ``` -So far, we've only added trait implementations to structs, but you can -implement a trait for any type. So technically, we _could_ implement -`HasArea` for `i32`: +So far, we’ve only added trait implementations to structs, but you can +implement a trait for any type. So technically, we _could_ implement `HasArea` +for `i32`: -```{rust} +```rust trait HasArea { fn area(&self) -> f64; } @@ -181,102 +173,57 @@ It is considered poor style to implement methods on such primitive types, even though it is possible. This may seem like the Wild West, but there are two other restrictions around -implementing traits that prevent this from getting out of hand. First, traits -must be `use`d in any scope where you wish to use the trait's method. So for -example, this does not work: +implementing traits that prevent this from getting out of hand. The first is +that if the trait isn’t defined in your scope, it doesn’t apply. Here’s an +example: the standard library provides a [`Write`][write] trait which adds +extra functionality to `File`s, for doing file I/O. By default, a `File` +won’t have its methods: -```{rust,ignore} -mod shapes { - use std::f64::consts; +[write]: ../std/io/trait.Write.html - trait HasArea { - fn area(&self) -> f64; - } - - struct Circle { - x: f64, - y: f64, - radius: f64, - } - - impl HasArea for Circle { - fn area(&self) -> f64 { - consts::PI * (self.radius * self.radius) - } - } -} - -fn main() { - let c = shapes::Circle { - x: 0.0f64, - y: 0.0f64, - radius: 1.0f64, - }; - - println!("{}", c.area()); -} +```rust,ignore +let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt"); +let result = f.write("whatever".as_bytes()); +# result.unwrap(); // ignore the erorr ``` -Now that we've moved the structs and traits into their own module, we get an -error: +Here’s the error: ```text -error: type `shapes::Circle` does not implement any method in scope named `area` -``` +error: type `std::fs::File` does not implement any method in scope named `write` -If we add a `use` line right above `main` and make the right things public, -everything is fine: - -```{rust} -# #![feature(core)] -mod shapes { - use std::f64::consts; - - pub trait HasArea { - fn area(&self) -> f64; - } - - pub struct Circle { - pub x: f64, - pub y: f64, - pub radius: f64, - } - - impl HasArea for Circle { - fn area(&self) -> f64 { - consts::PI * (self.radius * self.radius) - } - } -} +let result = f.write(b”whatever”); + ^~~~~~~~~~~~~~~~~~ +``` -use shapes::HasArea; +We need to `use` the `Write` trait first: -fn main() { - let c = shapes::Circle { - x: 0.0f64, - y: 0.0f64, - radius: 1.0f64, - }; +```rust,ignore +use std::io::Write; - println!("{}", c.area()); -} +let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt"); +let result = f.write("whatever".as_bytes()); +# result.unwrap(); // ignore the erorr ``` +This will compile without error. + This means that even if someone does something bad like add methods to `int`, -it won't affect you, unless you `use` that trait. +it won’t affect you, unless you `use` that trait. -There's one more restriction on implementing traits. Either the trait or the -type you're writing the `impl` for must be inside your crate. So, we could -implement the `HasArea` type for `i32`, because `HasArea` is in our crate. But +There’s one more restriction on implementing traits. Either the trait or the +type you’re writing the `impl` for must be defined by you. So, we could +implement the `HasArea` type for `i32`, because `HasArea` is in our code. But if we tried to implement `Float`, a trait provided by Rust, for `i32`, we could -not, because both the trait and the type aren't in our crate. +not, because neither the trait nor the type are in our code. One last thing about traits: generic functions with a trait bound use -*monomorphization* (*mono*: one, *morph*: form), so they are statically -dispatched. What's that mean? Check out the chapter on [trait -objects](trait-objects.html) for more. +‘monomorphization’ (mono: one, morph: form), so they are statically dispatched. +What’s that mean? Check out the chapter on [trait objects][to] for more details. + +[to]: trait-objects.html -## Multiple trait bounds +# Multiple trait bounds You’ve seen that you can bound a generic type parameter with a trait: @@ -299,10 +246,10 @@ fn foo(x: T) { `T` now needs to be both `Clone` as well as `Debug`. -## Where clause +# Where clause Writing functions with only a few generic types and a small number of trait -bounds isn't too bad, but as the number increases, the syntax gets increasingly +bounds isn’t too bad, but as the number increases, the syntax gets increasingly awkward: ``` @@ -318,7 +265,7 @@ fn foo(x: T, y: K) { The name of the function is on the far left, and the parameter list is on the far right. The bounds are getting in the way. -Rust has a solution, and it's called a '`where` clause': +Rust has a solution, and it’s called a ‘`where` clause’: ``` use std::fmt::Debug; @@ -389,84 +336,9 @@ This shows off the additional feature of `where` clauses: they allow bounds where the left-hand side is an arbitrary type (`i32` in this case), not just a plain type parameter (like `T`). -## Our `inverse` Example - -Back in [Generics](generics.html), we were trying to write code like this: - -```{rust,ignore} -fn inverse(x: T) -> Result { - if x == 0.0 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0 / x) -} -``` - -If we try to compile it, we get this error: - -```text -error: binary operation `==` cannot be applied to type `T` -``` - -This is because `T` is too generic: we don't know if a random `T` can be -compared. For that, we can use trait bounds. It doesn't quite work, but try -this: - -```{rust,ignore} -fn inverse(x: T) -> Result { - if x == 0.0 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0 / x) -} -``` - -You should get this error: - -```text -error: mismatched types: - expected `T`, - found `_` -(expected type parameter, - found floating-point variable) -``` - -So this won't work. While our `T` is `PartialEq`, we expected to have another `T`, -but instead, we found a floating-point variable. We need a different bound. `Float` -to the rescue: - -``` -# #![feature(std_misc)] -use std::num::Float; - -fn inverse(x: T) -> Result { - if x == Float::zero() { return Err("x cannot be zero!".to_string()) } - - let one: T = Float::one(); - Ok(one / x) -} -``` - -We've had to replace our generic `0.0` and `1.0` with the appropriate methods -from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function -works just fine: - -``` -# #![feature(std_misc)] -# use std::num::Float; -# fn inverse(x: T) -> Result { -# if x == Float::zero() { return Err("x cannot be zero!".to_string()) } -# let one: T = Float::one(); -# Ok(one / x) -# } -println!("the inverse of {} is {:?}", 2.0f32, inverse(2.0f32)); -println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64)); - -println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32)); -println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64)); -``` - -## Default methods +# Default methods -There's one last feature of traits we should cover: default methods. It's +There’s one last feature of traits we should cover: default methods. It’s easiest just to show an example: ```rust @@ -477,8 +349,8 @@ trait Foo { } ``` -Implementors of the `Foo` trait need to implement `bar()`, but they don't -need to implement `baz()`. They'll get this default behavior. They can +Implementors of the `Foo` trait need to implement `bar()`, but they don’t +need to implement `baz()`. They’ll get this default behavior. They can override the default if they so choose: ```rust @@ -506,3 +378,43 @@ default.baz(); // prints "We called baz." let over = OverrideDefault; over.baz(); // prints "Override baz!" ``` + +# Inheritance + +Sometimes, implementing a trait requires implementing another trait: + +```rust +trait Foo { + fn foo(&self); +} + +trait FooBar : Foo { + fn foobar(&self); +} +``` + +Implementors of `FooBar` must also implement `Foo`, like this: + +```rust +# trait Foo { +# fn foo(&self); +# } +# trait FooBar : Foo { +# fn foobar(&self); +# } +struct Baz; + +impl Foo for Baz { + fn foo(&self) { println!("foo"); } +} + +impl FooBar for Baz { + fn foobar(&self) { println!("foobar"); } +} +``` + +If we forget to implement `Foo`, Rust will tell us: + +```text +error: the trait `main::Foo` is not implemented for the type `main::Baz` [E0277] +``` From 1c48227b3c94a374c47fd5110bb76d48d7d5ada3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 17:23:00 -0400 Subject: [PATCH 15/23] Remove inverse example from generics part of TRPL Fixes #24325. --- src/doc/trpl/generics.md | 85 ---------------------------------------- 1 file changed, 85 deletions(-) diff --git a/src/doc/trpl/generics.md b/src/doc/trpl/generics.md index 3e4e0a66eae05..b13c68c45c870 100644 --- a/src/doc/trpl/generics.md +++ b/src/doc/trpl/generics.md @@ -90,88 +90,3 @@ if we wanted to. Convention says that the first generic parameter should be The `Result` type is intended to be used to return the result of a computation, and to have the ability to return an error if it didn't work out. -Here's an example: - -```{rust} -let x: Result = Ok(2.3f64); -let y: Result = Err("There was an error.".to_string()); -``` - -This particular Result will return an `f64` if there's a success, and a -`String` if there's a failure. Let's write a function that uses `Result`: - -```{rust} -fn inverse(x: f64) -> Result { - if x == 0.0f64 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0f64 / x) -} -``` - -We don't want to take the inverse of zero, so we check to make sure that we -weren't passed zero. If we were, then we return an `Err`, with a message. If -it's okay, we return an `Ok`, with the answer. - -Why does this matter? Well, remember how `match` does exhaustive matches? -Here's how this function gets used: - -```{rust} -# fn inverse(x: f64) -> Result { -# if x == 0.0f64 { return Err("x cannot be zero!".to_string()); } -# Ok(1.0f64 / x) -# } -let x = inverse(25.0f64); - -match x { - Ok(x) => println!("The inverse of 25 is {}", x), - Err(msg) => println!("Error: {}", msg), -} -``` - -The `match` enforces that we handle the `Err` case. In addition, because the -answer is wrapped up in an `Ok`, we can't just use the result without doing -the match: - -```{rust,ignore} -let x = inverse(25.0f64); -println!("{}", x + 2.0f64); // error: binary operation `+` cannot be applied - // to type `core::result::Result` -``` - -This function is great, but there's one other problem: it only works for 64 bit -floating point values. What if we wanted to handle 32 bit floating point as -well? We'd have to write this: - -```{rust} -fn inverse32(x: f32) -> Result { - if x == 0.0f32 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0f32 / x) -} -``` - -Bummer. What we need is a *generic function*. Luckily, we can write one! -However, it won't _quite_ work yet. Before we get into that, let's talk syntax. -A generic version of `inverse` would look something like this: - -```{rust,ignore} -fn inverse(x: T) -> Result { - if x == 0.0 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0 / x) -} -``` - -Just like how we had `Option`, we use a similar syntax for `inverse`. -We can then use `T` inside the rest of the signature: `x` has type `T`, and half -of the `Result` has type `T`. However, if we try to compile that example, we'll get -an error: - -```text -error: binary operation `==` cannot be applied to type `T` -``` - -Because `T` can be _any_ type, it may be a type that doesn't implement `==`, -and therefore, the first line would be wrong. What do we do? - -To fix this example, we need to learn about another Rust feature: traits. From 14af25797f99cb70379669fe17092fabcae6fabc Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 18 Apr 2015 17:37:49 -0400 Subject: [PATCH 16/23] TRPL edits: generics --- src/doc/trpl/generics.md | 112 +++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 40 deletions(-) diff --git a/src/doc/trpl/generics.md b/src/doc/trpl/generics.md index b13c68c45c870..517a6e6064253 100644 --- a/src/doc/trpl/generics.md +++ b/src/doc/trpl/generics.md @@ -1,31 +1,13 @@ % Generics Sometimes, when writing a function or data type, we may want it to work for -multiple types of arguments. For example, remember our `OptionalInt` type? +multiple types of arguments. Luckily, Rust has a feature that gives us a better +way: generics. Generics are called ‘parametric polymorphism’ in type theory, +which means that they are types or functions that have multiple forms (‘poly’ +is multiple, ‘morph’ is form) over a given parameter (‘parametric’). -```{rust} -enum OptionalInt { - Value(i32), - Missing, -} -``` - -If we wanted to also have an `OptionalFloat64`, we would need a new enum: - -```{rust} -enum OptionalFloat64 { - Valuef64(f64), - Missingf64, -} -``` - -This is really unfortunate. Luckily, Rust has a feature that gives us a better -way: generics. Generics are called *parametric polymorphism* in type theory, -which means that they are types or functions that have multiple forms (*poly* -is multiple, *morph* is form) over a given parameter (*parametric*). - -Anyway, enough with type theory declarations, let's check out the generic form -of `OptionalInt`. It is actually provided by Rust itself, and looks like this: +Anyway, enough with type theory, let’s check out some generic code. Rust’s +standard library provides a type, `Option`, that’s generic: ```rust enum Option { @@ -34,41 +16,40 @@ enum Option { } ``` -The `` part, which you've seen a few times before, indicates that this is +The `` part, which you’ve seen a few times before, indicates that this is a generic data type. Inside the declaration of our enum, wherever we see a `T`, -we substitute that type for the same type used in the generic. Here's an +we substitute that type for the same type used in the generic. Here’s an example of using `Option`, with some extra type annotations: -```{rust} +```rust let x: Option = Some(5); ``` In the type declaration, we say `Option`. Note how similar this looks to `Option`. So, in this particular `Option`, `T` has the value of `i32`. On the right-hand side of the binding, we do make a `Some(T)`, where `T` is `5`. -Since that's an `i32`, the two sides match, and Rust is happy. If they didn't -match, we'd get an error: +Since that’s an `i32`, the two sides match, and Rust is happy. If they didn’t +match, we’d get an error: -```{rust,ignore} +```rust,ignore let x: Option = Some(5); // error: mismatched types: expected `core::option::Option`, // found `core::option::Option<_>` (expected f64 but found integral variable) ``` -That doesn't mean we can't make `Option`s that hold an `f64`! They just have to -match up: +That doesn’t mean we can’t make `Option`s that hold an `f64`! They just have +to match up: -```{rust} +```rust let x: Option = Some(5); let y: Option = Some(5.0f64); ``` This is just fine. One definition, multiple uses. -Generics don't have to only be generic over one type. Consider Rust's built-in -`Result` type: +Generics don’t have to only be generic over one type. Consider another type from Rust’s standard library that’s similar, `Result`: -```{rust} +```rust enum Result { Ok(T), Err(E), @@ -76,9 +57,9 @@ enum Result { ``` This type is generic over _two_ types: `T` and `E`. By the way, the capital letters -can be any letter you'd like. We could define `Result` as: +can be any letter you’d like. We could define `Result` as: -```{rust} +```rust enum Result { Ok(A), Err(Z), @@ -86,7 +67,58 @@ enum Result { ``` if we wanted to. Convention says that the first generic parameter should be -`T`, for 'type,' and that we use `E` for 'error.' Rust doesn't care, however. +`T`, for ‘type’, and that we use `E` for ‘error’. Rust doesn’t care, however. The `Result` type is intended to be used to return the result of a -computation, and to have the ability to return an error if it didn't work out. +computation, and to have the ability to return an error if it didn’t work out. + +## Generic functions + +We can write functions that take generic types with a similar syntax: + +```rust +fn takes_anything(x: T) { + // do something with x +} +``` + +The syntax has two parts: the `` says “this function is generic over one +type, `T`”, and the `x: T` says “x has the type `T`.” + +Multiple arguments can have the same generic type: + +```rust +fn takes_two_of_the_same_things(x: T, y: T) { + // ... +} +``` + +We could write a version that takes multiple types: + +```rust +fn takes_two_things(x: T, y: U) { + // ... +} +``` + +Generic functions are most useful with ‘trait bounds’, which we’ll cover in the +[section on traits][traits]. + +[traits]: traits.html + +## Generic structs + +You can store a generic type in a `struct` as well: + +``` +struct Point { + x: T, + y: T, +} + +let int_origin = Point { x: 0, y: 0 }; +let float_origin = Point { x: 0.0, y: 0.0 }; +``` + +Similarly to functions, the `` is where we declare the generic parameters, +and we then use `x: T` in the type declaration, too. From 1dd8a651ba2a596b825afa6af8f7dd7cf5f524a1 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Apr 2015 09:55:07 -0400 Subject: [PATCH 17/23] Make iterator struct docs more consistent. Fixes #24008. --- src/libcore/str/mod.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 2d6ef39361e8a..5c862d73537ad 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -341,7 +341,7 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> { /// External iterator for a string's bytes. /// Use with the `std::iter` module. /// -/// Created with `str::bytes` +/// Created with the method `.bytes()`. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Bytes<'a>(Map, BytesDeref>); @@ -636,10 +636,10 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { generate_pattern_iterators! { forward: - /// Return type of `str::split()` + /// Created with the method `.split()`. struct Split; reverse: - /// Return type of `str::rsplit()` + /// Created with the method `.rsplit()`. struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -650,10 +650,10 @@ generate_pattern_iterators! { generate_pattern_iterators! { forward: - /// Return type of `str::split_terminator()` + /// Created with the method `.split_terminator()`. struct SplitTerminator; reverse: - /// Return type of `str::rsplit_terminator()` + /// Created with the method `.rsplit_terminator()`. struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -696,10 +696,10 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { generate_pattern_iterators! { forward: - /// Return type of `str::splitn()` + /// Created with the method `.splitn()`. struct SplitN; reverse: - /// Return type of `str::rsplitn()` + /// Created with the method `.rsplitn()`. struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -730,10 +730,10 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: - /// Return type of `str::match_indices()` + /// Created with the method `.match_indices()`. struct MatchIndices; reverse: - /// Return type of `str::rmatch_indices()` + /// Created with the method `.rmatch_indices()`. struct RMatchIndices; stability: #[unstable(feature = "core", @@ -771,10 +771,10 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: - /// Return type of `str::matches()` + /// Created with the method `.matches()`. struct Matches; reverse: - /// Return type of `str::rmatches()` + /// Created with the method `.rmatches()`. struct RMatches; stability: #[unstable(feature = "core", reason = "type got recently added")] @@ -783,7 +783,7 @@ generate_pattern_iterators! { delegate double ended; } -/// Return type of `str::lines()` +/// Created with the method `.lines()`. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Lines<'a>(SplitTerminator<'a, char>); @@ -811,7 +811,7 @@ impl<'a> DoubleEndedIterator for Lines<'a> { } } -/// Return type of `str::lines_any()` +/// Created with the method `.lines_any()`. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct LinesAny<'a>(Map, LinesAnyMap>); From 89ef6371e09519f595b3c9a090aa5aa48f0fe2b1 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Apr 2015 09:59:58 -0400 Subject: [PATCH 18/23] remove bad example from PartialEq docs Fixes #24173 --- src/libcore/cmp.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index efe1179621de5..dd59ceff577a8 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -14,27 +14,6 @@ //! implement comparison operators. Rust programs may implement `PartialOrd` to overload the `<`, //! `<=`, `>`, and `>=` operators, and may implement `PartialEq` to overload the `==` and `!=` //! operators. -//! -//! For example, to define a type with a customized definition for the PartialEq operators, you -//! could do the following: -//! -//! ``` -//! # #![feature(core)] -//! struct FuzzyNum { -//! num: i32, -//! } -//! -//! impl PartialEq for FuzzyNum { -//! // Our custom eq allows numbers which are near each other to be equal! :D -//! fn eq(&self, other: &FuzzyNum) -> bool { -//! (self.num - other.num).abs() < 5 -//! } -//! } -//! -//! // Now these binary operators will work when applied! -//! assert!(FuzzyNum { num: 37 } == FuzzyNum { num: 34 }); -//! assert!(FuzzyNum { num: 25 } != FuzzyNum { num: 57 }); -//! ``` #![stable(feature = "rust1", since = "1.0.0")] From ac09864c90914a2e92363a39a39cd4b074e4892b Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Apr 2015 10:05:57 -0400 Subject: [PATCH 19/23] Clean up Box documentation. Without the `box` keyword, one of these two reasons is not correct, so let's just eliminate this section and elaborate on the reason for the legit use case inline. Fixes #24511 --- src/liballoc/boxed.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 4468e425a852d..009266c3d2c61 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -10,14 +10,9 @@ //! A pointer type for heap allocation. //! -//! `Box`, casually referred to as a 'box', provides the simplest form of -//! heap allocation in Rust. Boxes provide ownership for this allocation, and -//! drop their contents when they go out of scope. -//! -//! Boxes are useful in two situations: recursive data structures, and -//! occasionally when returning data. [The Pointer chapter of the -//! Book](../../../book/pointers.html#best-practices-1) explains these cases in -//! detail. +//! `Box`, casually referred to as a 'box', provides the simplest form of heap allocation in +//! Rust. Boxes provide ownership for this allocation, and drop their contents when they go out of +//! scope. //! //! # Examples //! @@ -43,6 +38,16 @@ //! ``` //! //! This will print `Cons(1, Box(Cons(2, Box(Nil))))`. +//! +//! Recursive structures must be boxed, because if the definition of `Cons` looked like this: +//! +//! ```rust,ignore +//! Cons(T, List), +//! ``` +//! +//! It wouldn't work. This is because the size of a `List` depends on how many elements are in the +//! list, and so we don't know how much memory to allocate for a `Cons`. By introducing a `Box`, +//! which has a defined size, we know how big `Cons` needs to be. #![stable(feature = "rust1", since = "1.0.0")] From fbd3261e376ca9bbaf9cb5e50ad9fa71901aeb74 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Apr 2015 10:42:17 -0400 Subject: [PATCH 20/23] Fix small typo in TRPL intro --- src/doc/trpl/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index 8d3a6ec39864c..dfe837285c877 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -165,7 +165,7 @@ fn main() { Rust has [move semantics][move] by default, so if we want to make a copy of some data, we call the `clone()` method. In this example, `y` is no longer a reference -to the vector stored in `x`, but a copy of its first element, `"hello"`. Now +to the vector stored in `x`, but a copy of its first element, `"Hello"`. Now that we don’t have a reference, our `push()` works just fine. [move]: move-semantics.html From 9a650456117284bc8fb9aa5e976531ad539bcd7d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Apr 2015 11:55:21 -0400 Subject: [PATCH 21/23] TRPL: casting Due to documenting `transmute`, addresses part of #12905 --- src/doc/trpl/casting-between-types.md | 88 ++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/doc/trpl/casting-between-types.md b/src/doc/trpl/casting-between-types.md index 8bb0ec6db0256..90731b64a38dc 100644 --- a/src/doc/trpl/casting-between-types.md +++ b/src/doc/trpl/casting-between-types.md @@ -1,3 +1,89 @@ % Casting Between Types -Coming Soon +Rust, with its focus on safety, provides two different ways of casting +different types between each other. The first, `as`, is for safe casts. +In contrast, `transmute` allows for arbitrary casting, and is one of the +most dangerous features of Rust! + +# `as` + +The `as` keyword does basic casting: + +```rust +let x: i32 = 5; + +let y = x as i64; +``` + +It only allows certain kinds of casting, however: + +```rust,ignore +let a = [0u8, 0u8, 0u8, 0u8]; + +let b = a as u32; // four eights makes 32 +``` + +This errors with: + +```text +error: non-scalar cast: `[u8; 4]` as `u32` +let b = a as u32; // four eights makes 32 + ^~~~~~~~ +``` + +It’s a ‘non-scalar cast’ because we have multiple values here: the four +elements of the array. These kinds of casts are very dangerous, because they +make assumptions about the way that multiple underlying strucutres are +implemented. For this, we need something more dangerous. + +# `transmute` + +The `transmute` function is provided by a [compiler intrinsic][intrinsics], and +what it does is very simple, but very scary. It tells Rust to treat a value of +one type as though it were another type. It does this regardless of the +typechecking system, and just completely trusts you. + +[intrinsic]: intrinsics.html + +In our previous example, we know that an array of four `u8`s represents a `u32` +properly, and so we want to do the cast. Using `transmute` instead of `as`, +Rust lets us: + +```rust +use std::mem; + +unsafe { + let a = [0u8, 0u8, 0u8, 0u8]; + + let b = mem::transmute::<[u8; 4], u32>(a); +} +``` + +We have to wrap the operation in an `unsafe` block, but this will compile +successfully. Technically, only the `mem::transmute` call itself needs to be in +the block, but it's nice in this case to enclose everything related, so you +know where to look. In this case, the details about `a` are also important, and +so they're in the block. You'll see code in either style, sometimes the context +is too far away, and wrapping all of the code in `unsafe` isn't a great idea. + +While `transmute` does very little checking, it will at least make sure that +the types are the same size. This errors: + +```rust,ignore +use std::mem; + +unsafe { + let a = [0u8, 0u8, 0u8, 0u8]; + + let b = mem::transmute::<[u8; 4], u64>(a); +} +``` + +with: + +```text +error: transmute called on types with different sizes: [u8; 4] (32 bits) to u64 +(64 bits) +``` + +Other than that, you're on your own! From 0f20c9d8b7bd63b8e62db5fde172651d71580ec9 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Apr 2015 13:33:13 -0400 Subject: [PATCH 22/23] Remove feature gated examples from the reference. The slice patterns example was nice, so let's put it with the other slice pattern feature gate documentation. Fixes #24573 --- src/doc/reference.md | 137 ++++++--------------------------- src/doc/trpl/slice-patterns.md | 24 ++++++ 2 files changed, 46 insertions(+), 115 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index c159f6164c205..d918a320e63a9 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -973,8 +973,7 @@ Use declarations support a number of convenient shortcuts: An example of `use` declarations: -``` -# #![feature(core)] +```rust use std::option::Option::{Some, None}; use std::collections::hash_map::{self, HashMap}; @@ -1031,16 +1030,17 @@ declarations. An example of what will and will not work for `use` items: ``` -# #![feature(core)] # #![allow(unused_imports)] -use foo::core::iter; // good: foo is at the root of the crate use foo::baz::foobaz; // good: foo is at the root of the crate mod foo { - extern crate core; - use foo::core::iter; // good: foo is at crate root -// use core::iter; // bad: core is not at the crate root + mod example { + pub mod iter {} + } + + use foo::example::iter; // good: foo is at crate root +// use example::iter; // bad: core is not at the crate root use self::baz::foobaz; // good: self refers to module 'foo' use foo::bar::foobar; // good: foo is at crate root @@ -1368,9 +1368,7 @@ a = Animal::Cat; Enumeration constructors can have either named or unnamed fields: -``` -# #![feature(struct_variant)] -# fn main() { +```rust enum Animal { Dog (String, f64), Cat { name: String, weight: f64 } @@ -1378,7 +1376,6 @@ enum Animal { let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2); a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 }; -# } ``` In this example, `Cat` is a _struct-like enum variant_, @@ -1718,17 +1715,6 @@ Functions within external blocks are declared in the same way as other Rust functions, with the exception that they may not have a body and are instead terminated by a semicolon. -``` -# #![feature(libc)] -extern crate libc; -use libc::{c_char, FILE}; - -extern { - fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; -} -# fn main() {} -``` - Functions within external blocks may be called by Rust code, just like functions defined in Rust. The Rust compiler automatically translates between the Rust ABI and the foreign ABI. @@ -1739,7 +1725,7 @@ By default external blocks assume that the library they are calling uses the standard C "cdecl" ABI. Other ABIs may be specified using an `abi` string, as shown here: -```{.ignore} +```ignore // Interface to the Windows API extern "stdcall" { } ``` @@ -3231,55 +3217,7 @@ expression. In a pattern whose head expression has an `enum` type, a placeholder (`_`) stands for a *single* data field, whereas a wildcard `..` stands for *all* the -fields of a particular variant. For example: - -``` -#![feature(box_patterns)] -#![feature(box_syntax)] -enum List { Nil, Cons(X, Box>) } - -fn main() { - let x: List = List::Cons(10, box List::Cons(11, box List::Nil)); - - match x { - List::Cons(_, box List::Nil) => panic!("singleton list"), - List::Cons(..) => return, - List::Nil => panic!("empty list") - } -} -``` - -The first pattern matches lists constructed by applying `Cons` to any head -value, and a tail value of `box Nil`. The second pattern matches _any_ list -constructed with `Cons`, ignoring the values of its arguments. The difference -between `_` and `..` is that the pattern `C(_)` is only type-correct if `C` has -exactly one argument, while the pattern `C(..)` is type-correct for any enum -variant `C`, regardless of how many arguments `C` has. - -Used inside an array pattern, `..` stands for any number of elements, when the -`advanced_slice_patterns` feature gate is turned on. This wildcard can be used -at most once for a given array, which implies that it cannot be used to -specifically match elements that are at an unknown distance from both ends of a -array, like `[.., 42, ..]`. If preceded by a variable name, it will bind the -corresponding slice to the variable. Example: - -``` -# #![feature(advanced_slice_patterns, slice_patterns)] -fn is_symmetric(list: &[u32]) -> bool { - match list { - [] | [_] => true, - [x, inside.., y] if x == y => is_symmetric(inside), - _ => false - } -} - -fn main() { - let sym = &[0, 1, 4, 2, 4, 1, 0]; - let not_sym = &[0, 1, 7, 2, 4, 1, 0]; - assert!(is_symmetric(sym)); - assert!(!is_symmetric(not_sym)); -} -``` +fields of a particular variant. A `match` behaves differently depending on whether or not the head expression is an [lvalue or an rvalue](#lvalues,-rvalues-and-temporaries). If the head @@ -3298,30 +3236,15 @@ the inside of the match. An example of a `match` expression: ``` -#![feature(box_patterns)] -#![feature(box_syntax)] -# fn process_pair(a: i32, b: i32) { } -# fn process_ten() { } - -enum List { Nil, Cons(X, Box>) } - -fn main() { - let x: List = List::Cons(10, box List::Cons(11, box List::Nil)); +let x = 1; - match x { - List::Cons(a, box List::Cons(b, _)) => { - process_pair(a, b); - } - List::Cons(10, _) => { - process_ten(); - } - List::Nil => { - return; - } - _ => { - panic!(); - } - } +match x { + 1 => println!("one"), + 2 => println!("two"), + 3 => println!("three"), + 4 => println!("four"), + 5 => println!("five"), + _ => println!("something else"), } ``` @@ -3334,28 +3257,12 @@ Subpatterns can also be bound to variables by the use of the syntax `variable @ subpattern`. For example: ``` -#![feature(box_patterns)] -#![feature(box_syntax)] - -enum List { Nil, Cons(u32, Box) } +let x = 1; -fn is_sorted(list: &List) -> bool { - match *list { - List::Nil | List::Cons(_, box List::Nil) => true, - List::Cons(x, ref r @ box List::Cons(_, _)) => { - match *r { - box List::Cons(y, _) => (x <= y) && is_sorted(&**r), - _ => panic!() - } - } - } -} - -fn main() { - let a = List::Cons(6, box List::Cons(7, box List::Cons(42, box List::Nil))); - assert!(is_sorted(&a)); +match x { + e @ 1 ... 5 => println!("got a range element {}", e), + _ => println!("anything"), } - ``` Patterns can also dereference pointers by using the `&`, `&mut` and `box` diff --git a/src/doc/trpl/slice-patterns.md b/src/doc/trpl/slice-patterns.md index 4599333a77a05..de165b70fc402 100644 --- a/src/doc/trpl/slice-patterns.md +++ b/src/doc/trpl/slice-patterns.md @@ -16,3 +16,27 @@ fn main() { } ``` +The `advanced_slice_patterns` gate lets you use `..` to indicate any number of +elements inside a pattern matching a slice. This wildcard can only be used once +for a given array. If there's an identifier before the `..`, the result of the +slice will be bound to that name. For example: + +```rust +#![feature(advanced_slice_patterns, slice_patterns)] + +fn is_symmetric(list: &[u32]) -> bool { + match list { + [] | [_] => true, + [x, inside.., y] if x == y => is_symmetric(inside), + _ => false + } +} + +fn main() { + let sym = &[0, 1, 4, 2, 4, 1, 0]; + assert!(is_symmetric(sym)); + + let not_sym = &[0, 1, 7, 2, 4, 1, 0]; + assert!(!is_symmetric(not_sym)); +} +``` From 1e29abec59a0610eb87ab9222c9efa35c6c00f19 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 16 Apr 2015 23:46:47 -0400 Subject: [PATCH 23/23] Add common macros to TRPL Fixes #22621 --- src/doc/trpl/macros.md | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md index 6d21cb59383c7..604c4366ab711 100644 --- a/src/doc/trpl/macros.md +++ b/src/doc/trpl/macros.md @@ -653,6 +653,116 @@ macro_rules! bct { Exercise: use macros to reduce duplication in the above definition of the `bct!` macro. +# Common macros + +Here are some common macros you’ll see in Rust code. + +## panic! + +This macro causes the current thread to panic. You can give it a message +to panic with: + +```rust,no_run +panic!("oh no!"); +``` + +## vec! + +The `vec!` macro is used throughout the book, so you’ve probably seen it +already. It creates `Vec`s with ease: + +```rust +let v = vec![1, 2, 3, 4, 5]; +``` + +It also lets you make vectors with repeating values. For example, a hundred +zeroes: + +```rust +let v = vec![0; 100]; +``` + +## assert! and assert_eq! + +These two macros are used in tests. `assert!` takes a boolean, and `assert_eq!` +takes two values and compares them. Truth passes, success `panic!`s. Like +this: + +```rust,no_run +// A-ok! + +assert!(true); +assert_eq!(5, 3 + 2); + +// nope :( + +assert!(5 < 3); +assert_eq!(5, 3); +``` +## try! + +`try!` is used for error handling. It takes something that can return a +`Result`, and gives `T` if it’s a `Ok`, and `return`s with the +`Err(E)` if it’s that. Like this: + +```rust,no_run +use std::fs::File; + +fn foo() -> std::io::Result<()> { + let f = try!(File::create("foo.txt")); + + Ok(()) +} +``` + +This is cleaner than doing this: + +```rust,no_run +use std::fs::File; + +fn foo() -> std::io::Result<()> { + let f = File::create("foo.txt"); + + let f = match f { + Ok(t) => t, + Err(e) => return Err(e), + }; + + Ok(()) +} +``` + +## unreachable! + +This macro is used when you think some code should never execute: + +```rust +if false { + unreachable!(); +} +``` + +Sometimes, the compiler may make you have a different branch that you know +will never, ever run. In these cases, use this macro, so that if you end +up wrong, you’ll get a `panic!` about it. + +```rust +let x: Option = None; + +match x { + Some(_) => unreachable!(), + None => println!("I know x is None!"), +} +``` + +## unimplemented! + +The `unimplemented!` macro can be used when you’re trying to get your functions +to typecheck, and don’t want to worry about writing out the body of the +function. One example of this situation is implementing a trait with multiple +required methods, where you want to tackle one at a time. Define the others +as `unimplemented!` until you’re ready to write them. + # Procedural macros If Rust's macro system can't do what you need, you may want to write a