Auto merge of #24328 - Manishearth:rollup, r=Manishearth

This commit is contained in:
bors 2015-04-11 18:31:59 +00:00
commit 6790b0e519
55 changed files with 1587 additions and 1524 deletions

View file

@ -1,39 +1,192 @@
% The Rust Programming Language
Welcome! This book will teach you about [the Rust Programming
Language](http://www.rust-lang.org/). Rust is a modern systems programming
language focusing on safety and speed. It accomplishes these goals by being
memory safe without using garbage collection.
Welcome! This book will teach you about the [Rust Programming Language][rust].
Rust is a systems programming language focused on three goals: safety, speed,
and concurrency. It maintains these goals without having a garbage collector,
making it a useful language for a number of use cases other languages arent
good at: embedding in other languages, programs with specific space and time
requirements, and writing low-level code, like device drivers and operating
systems. It improves on current languages targeting this space by having a
number of compile-time safety checks that produce no runtime overhead, while
eliminating all data races. Rust also aims to achieve zero-cost abstrations
even though some of these abstractions feel like those of a high-level
language. Even then, Rust still allows precise control like a low-level
language would.
"The Rust Programming Language" is split into three sections, which you can
navigate through the menu on the left.
[rust]: http://rust-lang.org
<h2 class="section-header"><a href="basic.html">Basics</a></h2>
“The Rust Programming Language” is split into seven sections. This introduction
is the first. After this:
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.
* [Getting started][gs] - Set up your computer for Rust development.
* [Learn Rust][lr] - Learn Rust programming through small projects.
* [Effective Rust][er] - Higher-level concepts for writing excellent Rust code.
* [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks.
* [Nightly Rust][nr] - Cutting-edge features that arent in stable builds yet.
* [Glossary][gl] - A reference of terms used in the book.
After reading "Basics," you will have a good foundation to learn more about
Rust, and can write very simple programs.
[gs]: getting-started.html
[lr]: learn-rust.html
[er]: effective-rust.html
[ss]: syntax-and-semantics.html
[nr]: nightly-rust.html
[gl]: glossary.html
<h2 class="section-header"><a href="intermediate.html">Intermediate</a></h2>
After reading this introduction, youll want to dive into either Learn Rust
or Syntax and Semantics, depending on your preference: Learn Rust if you
want to dive in with a project, or Syntax and Semantics if you prefer to
start small, and learn a single concept thoroughly before moving onto the next.
Copious cross-linking connects these parts together.
This section contains individual chapters, which are self-contained. They focus
on specific topics, and can be read in any order.
## A brief introduction to Rust
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.
Is Rust a language you might be interested in? Lets examine a few small code
samples to show off a few of its strengths.
<h2 class="section-header"><a href="advanced.html">Advanced</a></h2>
The main concept that makes Rust unique is called ownership. Consider this
small example:
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 Rust's most complex features.
```rust
fn main() {
let mut x = vec!["Hello", "world"];
}
```
<h2 class="section-header"><a href="unstable.html">Unstable</a></h2>
This program makes a [variable binding][var] named `x`. The value of this
binding is a `Vec<T>`, a vector, that we create through a [macro][macro]
defined in the standard library. This macro is called `vec`, and we invoke
macros with a `!`. This follows a general principle of Rust: make things
explicit. Macros can do significantly more complicated things than function
calls, and so theyre visually distinct. The `!` also helps with parsing,
making tooling easier to write, which is also important.
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.
We used `mut` to make `x` mutable: bindings are immutable by default in Rust.
Well be mutating this vector later in the example.
This chapter contains things that are only available on the nightly channel of
Rust.
Its also worth noting that we didnt need a type annotation here: while Rust
is statically typed, we didnt need to explicitly annotate the type. Rust has
type inference to balance out the power of static typing with the verbosity of
annotating types.
Rust prefers stack allocation to heap allocation: `x` is placed directly on the
stack. However, the `Vec<T>` type allocates space for the elements of the
vector on the heap. If youre not familiar with this distinction, you can
ignore it for now, or check out [The Stack and the Heap][heap]. As a systems
programming language, Rust gives you the ability to control how your memory is
allocated, but when were getting started, its less of a big deal.
[var]: variable-bindings.html
[macro]: macros.html
[heap]: the-stack-and-the-heap.html
Earlier, we mentioned that ownership is the key new concept in Rust. In Rust
parlance, `x` is said to own the vector. This means that when `x` goes out of
scope, the vectors memory will be de-allocated. This is done deterministically
by the Rust compiler, rather than through a mechanism such as a garbage
collector. In other words, in Rust, you dont call functions like `malloc` and
`free` yourself: the compiler statically determines when you need to allocate
or deallocate memory, and inserts those calls itself. To err is to be human,
but compilers never forget.
Lets add another line to our example:
```rust
fn main() {
let mut x = vec!["Hello", "world"];
let y = &x[0];
}
```
Weve introduced another binding, `y`. In this case, `y` is a reference to
the first element of the vector. Rusts references are similar to pointers in
other languages, but with additional compile-time safety checks. References
interact with the ownership system by [borrowing][borrowing] what they point
to, rather than owning it. The difference is, when the reference goes out of
scope, it will not deallocate the underlying memory. If it did, wed
de-allocate twice, which is bad!
[borrowing]: references-and-borrowing.html
Lets add a third line. It looks innocent enough, but causes a compiler error:
```rust,ignore
fn main() {
let mut x = vec!["Hello", "world"];
let y = &x[0];
x.push("foo");
}
```
`push` is a method on vectors that appends another element to the end of the
vector. When we try to compile this program, we get an error:
```text
error: cannot borrow `x` as mutable because it is also borrowed as immutable
x.push(4);
^
note: previous borrow of `x` occurs here; the immutable borrow prevents
subsequent moves or mutable borrows of `x` until the borrow ends
let y = &x[0];
^
note: previous borrow ends here
fn main() {
}
^
```
Whew! The Rust compiler gives quite detailed errors at times, and this is one
of those times. As the error explains, while we made our binding mutable, we
still cannot call `push`. This is because we already have a reference to an
element of the vector, `y`. Mutating something while another reference exists
is dangerous, because we may invalidate the reference. In this specific case,
when we create the vector, we may have only allocated space for three elements.
Adding a fourth would mean allocating a new chunk of memory for all those elements,
copying the old values over, and updating the internal pointer to that memory.
That all works just fine. The problem is that `y` wouldnt get updated, and so
wed have a dangling pointer. Thats bad. Any use of `y` would be an error in
this case, and so the compiler has caught this for us.
So how do we solve this problem? There are two approaches we can take. The first
is making a copy rather than using a reference:
```rust
fn main() {
let mut x = vec!["Hello", "world"];
let y = x[0].clone();
x.push("foo");
}
```
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
that we dont have a reference, our `push()` works just fine.
[move]: move-semantics.html
If we truly want a reference, we need the other option: ensure that our reference
goes out of scope before we try to do the mutation. That looks like this:
```rust
fn main() {
let mut x = vec!["Hello", "world"];
{
let y = &x[0];
}
x.push("foo");
}
```
We created an inner scope with an additional set of curly braces. `y` will go out of
scope before we call `push()`, and so were all good.
This concept of ownership isnt just good for preventing danging pointers, but an
entire set of related problems, like iterator invalidation, concurrency, and more.

View file

@ -7,47 +7,45 @@
* [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)
* [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)
* [Deref coercions](deref-coercions.md)
* [Syntax and Semantics](syntax-and-semantics.md)
* [Variable Bindings](variable-bindings.md)
* [Primitive Types](primitive-types.md)
* [Functions](functions.md)
* [Primitive Types](primitive-types.md)
* [Comments](comments.md)
* [Structs](structs.md)
* [Mutability](mutability.md)
* [Method Syntax](method-syntax.md)
* [Enums](enums.md)
* [`if`](if.md)
* [Match](match.md)
* [Patterns](patterns.md)
* [`for` loops](for-loops.md)
* [`while` loops](while-loops.md)
* [if](if.md)
* [for loops](for-loops.md)
* [while loops](while-loops.md)
* [Ownership](ownership.md)
* [References and Borrowing](references-and-borrowing.md)
* [Lifetimes](lifetimes.md)
* [Mutability](mutability.md)
* [Move semantics](move-semantics.md)
* [Enums](enums.md)
* [Match](match.md)
* [Patterns](patterns.md)
* [Structs](structs.md)
* [Method Syntax](method-syntax.md)
* [Drop](drop.md)
* [Vectors](vectors.md)
* [Arrays](arrays.md)
* [Slices](slices.md)
* [Strings](strings.md)
* [Traits](traits.md)
* [Operators and Overloading](operators-and-overloading.md)
* [Generics](generics.md)
* [if let](if-let.md)
* [Trait Objects](trait-objects.md)
* [Closures](closures.md)
* [Universal Function Call Syntax](ufcs.md)
* [Crates and Modules](crates-and-modules.md)
* [`static`](static.md)
* [`const`](const.md)
* [Tuples](tuples.md)
* [Tuple Structs](tuple-structs.md)
* [Attributes](attributes.md)
* [Conditional Compilation](conditional-compilation.md)
@ -66,4 +64,6 @@
* [Link args](link-args.md)
* [Benchmark Tests](benchmark-tests.md)
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
* [Slice Patterns](slice-patterns.md)
* [Glossary](glossary.md)
* [Academic Research](academic-research.md)

View file

@ -0,0 +1,46 @@
% Academic Research
An incomplete list of papers that have had some influence in Rust.
Recommended for inspiration and a better understanding of Rust's background.
### Type system
* [Region based memory management in Cyclone](http://209.68.42.137/ucsd-pages/Courses/cse227.w03/handouts/cyclone-regions.pdf)
* [Safe manual memory management in Cyclone](http://www.cs.umd.edu/projects/PL/cyclone/scp.pdf)
* [Typeclasses: making ad-hoc polymorphism less ad hoc](http://www.ps.uni-sb.de/courses/typen-ws99/class.ps.gz)
* [Macros that work together](https://www.cs.utah.edu/plt/publications/jfp12-draft-fcdf.pdf)
* [Traits: composable units of behavior](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf)
* [Alias burying](http://www.cs.uwm.edu/faculty/boyland/papers/unique-preprint.ps) - We tried something similar and abandoned it.
* [External uniqueness is unique enough](http://www.computingscience.nl/research/techreps/repo/CS-2002/2002-048.pdf)
* [Uniqueness and Reference Immutability for Safe Parallelism](https://research.microsoft.com/pubs/170528/msr-tr-2012-79.pdf)
* [Region Based Memory Management](http://www.cs.ucla.edu/~palsberg/tba/papers/tofte-talpin-iandc97.pdf)
### Concurrency
* [Singularity: rethinking the software stack](https://research.microsoft.com/pubs/69431/osr2007_rethinkingsoftwarestack.pdf)
* [Language support for fast and reliable message passing in singularity OS](https://research.microsoft.com/pubs/67482/singsharp.pdf)
* [Scheduling multithreaded computations by work stealing](http://supertech.csail.mit.edu/papers/steal.pdf)
* [Thread scheduling for multiprogramming multiprocessors](http://www.eecis.udel.edu/%7Ecavazos/cisc879-spring2008/papers/arora98thread.pdf)
* [The data locality of work stealing](http://www.aladdin.cs.cmu.edu/papers/pdfs/y2000/locality_spaa00.pdf)
* [Dynamic circular work stealing deque](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.170.1097&rep=rep1&type=pdf) - The Chase/Lev deque
* [Work-first and help-first scheduling policies for async-finish task parallelism](http://www.cs.rice.edu/%7Eyguo/pubs/PID824943.pdf) - More general than fully-strict work stealing
* [A Java fork/join calamity](http://www.coopsoft.com/ar/CalamityArticle.html) - critique of Java's fork/join library, particularly its application of work stealing to non-strict computation
* [Scheduling techniques for concurrent systems](http://www.ece.rutgers.edu/%7Eparashar/Classes/ece572-papers/05/ps-ousterhout.pdf)
* [Contention aware scheduling](http://www.blagodurov.net/files/a8-blagodurov.pdf)
* [Balanced work stealing for time-sharing multicores](http://www.cse.ohio-state.edu/hpcs/WWW/HTML/publications/papers/TR-12-1.pdf)
* [Three layer cake](http://www.upcrc.illinois.edu/workshops/paraplop10/papers/paraplop10_submission_8.pdf)
* [Non-blocking steal-half work queues](http://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf)
* [Reagents: expressing and composing fine-grained concurrency](http://www.mpi-sws.org/~turon/reagents.pdf)
* [Algorithms for scalable synchronization of shared-memory multiprocessors](https://www.cs.rochester.edu/u/scott/papers/1991_TOCS_synch.pdf)
### Others
* [Crash-only software](https://www.usenix.org/legacy/events/hotos03/tech/full_papers/candea/candea.pdf)
* [Composing High-Performance Memory Allocators](http://people.cs.umass.edu/~emery/pubs/berger-pldi2001.pdf)
* [Reconsidering Custom Memory Allocation](http://people.cs.umass.edu/~emery/pubs/berger-oopsla2002.pdf)
### Papers *about* Rust
* [GPU programming in Rust](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf)
* [Parallel closures: a new twist on an old idea](https://www.usenix.org/conference/hotpar12/parallel-closures-new-twist-old-idea) - not exactly about rust, but by nmatsakis

View file

@ -1,48 +0,0 @@
% 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.

View file

@ -1,3 +1,3 @@
% `Debug` and `Display`
% Debug and Display
Coming soon!

View file

@ -1 +1,8 @@
% Effective Rust
So youve learned how to write some Rust code. But theres a difference between
writing *any* Rust code and writing *good* Rust code.
This section consists of relatively independent tutorials which show you how to
take your Rust to the next level. Common patterns and standard library features
will be introduced. Read these sections in any order of your choosing.

View file

@ -1,10 +1,10 @@
% `for` Loops
% 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:
The `for` loop is used to loop a particular number of times. Rusts `for` loops
work a bit differently than in other systems languages, however. Rusts `for`
loop doesnt look like this “C-style” `for` loop:
```{c}
```c
for (x = 0; x < 10; x++) {
printf( "%d\n", x );
}
@ -12,7 +12,7 @@ for (x = 0; x < 10; x++) {
Instead, it looks like this:
```{rust}
```rust
for x in 0..10 {
println!("{}", x); // x: i32
}
@ -20,25 +20,24 @@ for x in 0..10 {
In slightly more abstract terms,
```{ignore}
```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.
The expression is an [iterator][iterator]. 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.
[iterator]: iterators.html
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
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.

View file

@ -1 +1,5 @@
% Getting Started
This first section of the book will get you going with Rust and its tooling.
First, well install Rust. Then: the classic Hello World program. Finally,
well talk about Cargo, Rusts build system and package manager.

View file

@ -1,26 +1,27 @@
% Hello, Cargo!
[Cargo](http://crates.io) is a tool that Rustaceans use to help manage their
Rust projects. Cargo is currently in a pre-1.0 state, just like Rust, and so it
is still a work in progress. However, it is already good enough to use for many
Rust projects, and so it is assumed that Rust projects will use Cargo from the
beginning.
[Cargo][cratesio] is a tool that Rustaceans use to help manage their Rust
projects. Cargo is currently in a pre-1.0 state, and so it is still a work in
progress. However, it is already good enough to use for many Rust projects, and
so it is assumed that Rust projects will use Cargo from the beginning.
[cratesio]: https://doc.crates.io
Cargo manages three things: building your code, downloading the dependencies
your code needs, and building those dependencies. At first, your
program doesn't have any dependencies, so we'll only be using the first part of
its functionality. Eventually, we'll add more. Since we started off by using
program doesnt have any dependencies, so well only be using the first part of
its functionality. Eventually, well add more. Since we started off by using
Cargo, it'll be easy to add later.
If you installed Rust via the official installers you will also have
Cargo. If you installed Rust some other way, you may want to [check
the Cargo
README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies)
for specific instructions about installing it.
If you installed Rust via the official installers you will also have Cargo. If
you installed Rust some other way, you may want to [check the Cargo
README][cargoreadme] for specific instructions about installing it.
[cargoreadme]: https://github.com/rust-lang/cargo#installing-cargo-from-nightlies
## Converting to Cargo
Let's convert Hello World to Cargo.
Lets convert Hello World to Cargo.
To Cargo-ify our project, we need to do two things: Make a `Cargo.toml`
configuration file, and put our source file in the right place. Let's
@ -52,14 +53,9 @@ Put this inside:
name = "hello_world"
version = "0.0.1"
authors = [ "Your name <you@example.com>" ]
[[bin]]
name = "hello_world"
```
This file is in the [TOML](https://github.com/toml-lang/toml) format. Let's let
it explain itself to you:
This file is in the [TOML][toml] format. Lets let it explain itself to you:
> TOML aims to be a minimal configuration file format that's easy to read due
> to obvious semantics. TOML is designed to map unambiguously to a hash table.
@ -68,10 +64,7 @@ it explain itself to you:
TOML is very similar to INI, but with some extra goodies.
Anyway, there are two *tables* in this file: `package` and `bin`. The first
tells Cargo metadata about your package. The second tells Cargo that we're
interested in building a binary, not a library (though we could do both!), as
well as what it is named.
[toml]: https://github.com/toml-lang/toml
Once you have this file in place, we should be ready to build! Try this:
@ -83,13 +76,32 @@ Hello, world!
```
Bam! We build our project with `cargo build`, and run it with
`./target/debug/hello_world`. This hasn't bought us a whole lot over our simple use
of `rustc`, but think about the future: when our project has more than one
file, we would need to call `rustc` more than once and pass it a bunch of options to
tell it to build everything together. With Cargo, as our project grows, we can
just `cargo build`, and it'll work the right way. When your project is finally
ready for release, you can use `cargo build --release` to compile your crates with
optimizations.
`./target/debug/hello_world`. We can do both in one step with `cargo run`:
```bash
$ cargo run
Running `target/debug/hello_world`
Hello, world!
```
Notice that we didnt re-build the project this time. Cargo figured out that
we hadnt changed the source file, and so it just ran the binary. If we had
made a modification, we would have seen it do both:
```bash
$ cargo build
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
Running `target/debug/hello_world`
Hello, world!
```
This hasnt bought us a whole lot over our simple use of `rustc`, but think
about the future: when our project gets more complex, we would need to do more
things to get all of the parts to properly compile. With Cargo, as our project
grows, we can just `cargo build`, and itll work the right way.
When your project is finally ready for release, you can use
`cargo build --release` to compile your project with optimizations.
You'll also notice that Cargo has created a new file: `Cargo.lock`.
@ -100,18 +112,25 @@ version = "0.0.1"
```
This file is used by Cargo to keep track of dependencies in your application.
Right now, we don't have any, so it's a bit sparse. You won't ever need
Right now, we dont have any, so its a bit sparse. You won't ever need
to touch this file yourself, just let Cargo handle it.
That's it! We've successfully built `hello_world` with Cargo. Even though our
program is simple, it's using much of the real tooling that you'll use for the
rest of your Rust career.
Thats it! Weve successfully built `hello_world` with Cargo. Even though our
program is simple, its using much of the real tooling that youll use for the
rest of your Rust career. You can expect to do this to get started with
virtually all Rust projects:
```bash
$ git clone someurl.com/foo
$ cd foo
$ cargo build
```
## A New Project
You don't have to go through this whole process every time you want to start a new
project! Cargo has the ability to make a bare-bones project directory in which you
can start developing right away.
You dont have to go through this whole process every time you want to start a
new project! Cargo has the ability to make a bare-bones project directory in
which you can start developing right away.
To start a new project with Cargo, use `cargo new`:
@ -119,8 +138,8 @@ To start a new project with Cargo, use `cargo new`:
$ cargo new hello_world --bin
```
We're passing `--bin` because we're making a binary program: if we
were making a library, we'd leave it off.
Were passing `--bin` because we're making a binary program: if we were making
a library, we'd leave it off.
Let's check out what Cargo has generated for us:
@ -135,10 +154,10 @@ $ tree .
1 directory, 2 files
```
If you don't have the `tree` command, you can probably get it from your distro's package
manager. It's not necessary, but it's certainly useful.
If you don't have the `tree` command, you can probably get it from your
distributions package manager. Its not necessary, but its certainly useful.
This is all we need to get started. First, let's check out `Cargo.toml`:
This is all we need to get started. First, lets check out `Cargo.toml`:
```toml
[package]
@ -148,11 +167,11 @@ version = "0.0.1"
authors = ["Your Name <you@example.com>"]
```
Cargo has populated this file with reasonable defaults based off the arguments you gave
it and your `git` global configuration. You may notice that Cargo has also initialized
the `hello_world` directory as a `git` repository.
Cargo has populated this file with reasonable defaults based off the arguments
you gave it and your `git` global configuration. You may notice that Cargo has
also initialized the `hello_world` directory as a `git` repository.
Here's what's in `src/main.rs`:
Heres whats in `src/main.rs`:
```rust
fn main() {
@ -160,9 +179,20 @@ fn main() {
}
```
Cargo has generated a "Hello World!" for us, and you're ready to start coding! A
much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html).
Cargo has generated a "Hello World!" for us, and youre ready to start coding! Cargo
has its own [guide][guide] which covers Cargos features in much more depth.
Now that you've got the tools down, let's actually learn more about the Rust
[guide]: http://doc.crates.io/guide.html
Now that youve got the tools down, lets actually learn more about the Rust
language itself. These are the basics that will serve you well through the rest
of your time with Rust.
You have two options: Dive into a project with [Learn Rust][learnrust], or
start from the bottom and work your way up with [Syntax and
Semantics][syntax]. More experienced systems programmers will probably prefer
Learn Rust, while those from dynamic backgrounds may enjoy either. Different
people learn differently! Choose whatevers right for you.
[learnrust]: learn-rust.html
[syntax]: syntax-and-semantics.html

View file

@ -1,9 +1,9 @@
% Hello, world!
Now that you have Rust installed, let's write your first Rust program. It's
Now that you have Rust installed, lets write your first Rust program. Its
traditional to make your first program in any new language one that prints the
text "Hello, world!" to the screen. The nice thing about starting with such a
simple program is that you can verify that your compiler isn't just installed,
text “Hello, world!” to the screen. The nice thing about starting with such a
simple program is that you can verify that your compiler isnt just installed,
but also working properly. And printing information to the screen is a pretty
common thing to do.
@ -12,38 +12,37 @@ to make a `projects` directory in my home directory, and keep all my projects
there. Rust does not care where your code lives.
This actually leads to one other concern we should address: this guide will
assume that you have basic familiarity with the command line. Rust does not
require that you know a whole ton about the command line, but until the
language is in a more finished state, IDE support is spotty. Rust makes no
specific demands on your editing tooling, or where your code lives.
assume that you have basic familiarity with the command line. Rust itself makes
no specific demands on your editing tooling, or where your code lives. If you
prefer an IDE to the command line, you may want to check out
[SolidOak][solidoak], or wherever plugins are for your favorite IDE. There are
a number of extensions of varying quality in development by the community. The
Rust team also ships [plugins for various editors][plugins]. Configuring your
editor or IDE is out of the scope of this tutorial, so check the documentation
for your setup, specifically.
With that said, let's make a directory in our projects directory.
[solidoak]: https://github.com/oakes/SolidOak
[plugins]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md
```{bash}
With that said, lets make a directory in our projects directory.
```bash
$ mkdir ~/projects
$ cd ~/projects
$ mkdir hello_world
$ cd hello_world
```
If you're on Windows and not using PowerShell, the `~` may not work. Consult
If youre on Windows and not using PowerShell, the `~` may not work. Consult
the documentation for your shell for more details.
Let's make a new source file next. I'm going to use the syntax `editor
filename` to represent editing a file in these examples, but you should use
whatever method you want. We'll call our file `main.rs`:
Lets make a new source file next. Well call our file `main.rs`. Rust files
always end in a `.rs` extension. If youre using more than one word in your
filename, use an underscore: `hello_world.rs` rather than `helloworld.rs`.
```{bash}
$ editor main.rs
```
Now that youve got your file open, type this in:
Rust files always end in a `.rs` extension. If you're using more than one word
in your filename, use an underscore. `hello_world.rs` rather than
`helloworld.rs`.
Now that you've got your file open, type this in:
```{rust}
```rust
fn main() {
println!("Hello, world!");
}
@ -51,89 +50,90 @@ fn main() {
Save the file, and then type this into your terminal window:
```{bash}
```bash
$ rustc main.rs
$ ./main # or main.exe on Windows
Hello, world!
```
You can also run these examples on [play.rust-lang.org](http://play.rust-lang.org/) by clicking on the arrow that appears in the upper right of the example when you mouse over the code.
Success! Lets go over what just happened in detail.
Success! Let's go over what just happened in detail.
```{rust}
```rust
fn main() {
}
```
These lines define a *function* in Rust. The `main` function is special:
it's the beginning of every Rust program. The first line says "I'm declaring a
function named `main`, which takes no arguments and returns nothing." If there
it's the beginning of every Rust program. The first line says "Im declaring a
function named `main` which takes no arguments and returns nothing." If there
were arguments, they would go inside the parentheses (`(` and `)`), and because
we aren't returning anything from this function, we can omit the return type
entirely. We'll get to it later.
we arent returning anything from this function, we can omit the return type
entirely. Well get to it later.
You'll also note that the function is wrapped in curly braces (`{` and `}`).
Youll also note that the function is wrapped in curly braces (`{` and `}`).
Rust requires these around all function bodies. It is also considered good
style to put the opening curly brace on the same line as the function
declaration, with one space in between.
Next up is this line:
```{rust}
```rust
println!("Hello, world!");
```
This line does all of the work in our little program. There are a number of
details that are important here. The first is that it's indented with four
details that are important here. The first is that its indented with four
spaces, not tabs. Please configure your editor of choice to insert four spaces
with the tab key. We provide some [sample configurations for various
editors][configs].
[configs]: https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md
The second point is the `println!()` part. This is calling a Rust *macro*,
The second point is the `println!()` part. This is calling a Rust [macro][macro],
which is how metaprogramming is done in Rust. If it were a function instead, it
would look like this: `println()`. For our purposes, we don't need to worry
about this difference. Just know that sometimes, you'll see a `!`, and that
means that you're calling a macro instead of a normal function. Rust implements
`println!` as a macro rather than a function for good reasons, but that's a
very advanced topic. You'll learn more when we talk about macros later. One
last thing to mention: Rust's macros are significantly different from C macros,
if you've used those. Don't be scared of using macros. We'll get to the details
eventually, you'll just have to trust us for now.
would look like this: `println()`. For our purposes, we dont need to worry
about this difference. Just know that sometimes, youll see a `!`, and that
means that youre calling a macro instead of a normal function. Rust implements
`println!` as a macro rather than a function for good reasons, but that's an
advanced topic. One last thing to mention: Rusts macros are significantly
different from C macros, if youve used those. Dont be scared of using macros.
Well get to the details eventually, youll just have to trust us for now.
Next, `"Hello, world!"` is a *string*. Strings are a surprisingly complicated
topic in a systems programming language, and this is a *statically allocated*
string. We will talk more about different kinds of allocation later. We pass
this string as an argument to `println!`, which prints the string to the
screen. Easy enough!
[macro]: macros.html
Finally, the line ends with a semicolon (`;`). Rust is an *expression
oriented* language, which means that most things are expressions. The `;` is
used to indicate that this expression is over, and the next one is ready to
begin. Most lines of Rust code end with a `;`. We will cover this in-depth
later in the guide.
Next, `"Hello, world!"` is a string. Strings are a surprisingly complicated
topic in a systems programming language, and this is a statically allocated
string. If you want to read further about allocation, check out [the stack and
the heap], but you dont need to right now if you dont want to. We pass this
string as an argument to `println!`, which prints the string to the screen.
Easy enough!
Finally, actually *compiling* and *running* our program. We can compile
with our compiler, `rustc`, by passing it the name of our source file:
[allocation]: the-stack-and-the-heap.html
```{bash}
Finally, the line ends with a semicolon (`;`). Rust is an expression oriented
language, which means that most things are expressions, rather than statements.
The `;` is used to indicate that this expression is over, and the next one is
ready to begin. Most lines of Rust code end with a `;`.
Finally, actually compiling and running our program. We can compile with our
compiler, `rustc`, by passing it the name of our source file:
```bash
$ rustc main.rs
```
This is similar to `gcc` or `clang`, if you come from a C or C++ background. Rust
will output a binary executable. You can see it with `ls`:
```{bash}
```bash
$ ls
main main.rs
```
Or on Windows:
```{bash}
```bash
$ dir
main.exe main.rs
```
@ -141,7 +141,7 @@ main.exe main.rs
There are now two files: our source code, with the `.rs` extension, and the
executable (`main.exe` on Windows, `main` everywhere else)
```{bash}
```bash
$ ./main # or main.exe on Windows
```
@ -149,15 +149,15 @@ This prints out our `Hello, world!` text to our terminal.
If you come from a dynamically typed language like Ruby, Python, or JavaScript,
you may not be used to these two steps being separate. Rust is an
*ahead-of-time compiled language*, which means that you can compile a
program, give it to someone else, and they don't need to have Rust installed.
If you give someone a `.rb` or `.py` or `.js` file, they need to have a
ahead-of-time compiled language, which means that you can compile a program,
give it to someone else, and they don't need to have Rust installed. If you
give someone a `.rb` or `.py` or `.js` file, they need to have a
Ruby/Python/JavaScript implementation installed, but you just need one command
to both compile and run your program. Everything is a tradeoff in language design,
and Rust has made its choice.
to both compile and run your program. Everything is a tradeoff in language
design, and Rust has made its choice.
Congratulations! You have officially written a Rust program. That makes you a
Rust programmer! Welcome.
Rust programmer! Welcome. 🎊🎉👍
Next, I'd like to introduce you to another tool, Cargo, which is used to write
real-world Rust programs. Just using `rustc` is nice for simple things, but as

3
src/doc/trpl/if-let.md Normal file
View file

@ -0,0 +1,3 @@
% if let
COMING SOON

View file

@ -1,10 +1,10 @@
% `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
systems language. So let's talk about it, to make sure you grasp the nuances.
Rusts take on `if` is not particularly complex, but its much more like the
`if` youll find in a dynamically typed language than in a more traditional
systems language. So lets talk about it, to make sure you grasp the nuances.
`if` is a specific form of a more general concept, the *branch*. The name comes
`if` is a specific form of a more general concept, the branch. The name comes
from a branch in a tree: a decision point, where depending on a choice,
multiple paths can be taken.
@ -20,11 +20,11 @@ if x == 5 {
If we changed the value of `x` to something else, this line would not print.
More specifically, if the expression after the `if` evaluates to `true`, then
the block is executed. If it's `false`, then it is not.
the block is executed. If its `false`, then it is not.
If you want something to happen in the `false` case, use an `else`:
```{rust}
```rust
let x = 5;
if x == 5 {
@ -50,8 +50,7 @@ if x == 5 {
This is all pretty standard. However, you can also do this:
```{rust}
```rust
let x = 5;
let y = if x == 5 {
@ -63,95 +62,12 @@ let y = if x == 5 {
Which we can (and probably should) write like this:
```{rust}
```rust
let x = 5;
let y = if x == 5 { 10 } else { 15 }; // y: i32
```
This reveals two interesting things about Rust: it is an expression-based
language, and semicolons are different from semicolons in other 'curly brace
and semicolon'-based languages. These two things are related.
## Expressions vs. Statements
Rust is primarily an expression based language. There are only two kinds of
statements, and everything else is an expression.
So what's the difference? Expressions return a value, and statements do not.
In many languages, `if` is a statement, and therefore, `let x = if ...` would
make no sense. But in Rust, `if` is an expression, which means that it returns
a value. We can then use this value to initialize the binding.
Speaking of which, bindings are a kind of the first of Rust's two statements.
The proper name is a *declaration statement*. So far, `let` is the only kind
of declaration statement we've seen. Let's talk about that some more.
In some languages, variable bindings can be written as expressions, not just
statements. Like Ruby:
```{ruby}
x = y = 5
```
In Rust, however, using `let` to introduce a binding is _not_ an expression. The
following will produce a compile-time error:
```{ignore}
let x = (let y = 5); // expected identifier, found keyword `let`
```
The compiler is telling us here that it was expecting to see the beginning of
an expression, and a `let` can only begin a statement, not an expression.
Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
expression, although its value is not particularly useful. Unlike C, where an
assignment evaluates to the assigned value (e.g. `5` in the previous example),
in Rust the value of an assignment is the unit type `()` (which we'll cover later).
The second kind of statement in Rust is the *expression statement*. Its
purpose is to turn any expression into a statement. In practical terms, Rust's
grammar expects statements to follow other statements. This means that you use
semicolons to separate expressions from each other. This means that Rust
looks a lot like most other languages that require you to use semicolons
at the end of every line, and you will see semicolons at the end of almost
every line of Rust code you see.
What is this exception that makes us say "almost"? You saw it already, in this
code:
```{rust}
let x = 5;
let y: i32 = if x == 5 { 10 } else { 15 };
```
Note that I've added the type annotation to `y`, to specify explicitly that I
want `y` to be an integer.
This is not the same as this, which won't compile:
```{ignore}
let x = 5;
let y: i32 = if x == 5 { 10; } else { 15; };
```
Note the semicolons after the 10 and 15. Rust will give us the following error:
```text
error: mismatched types: expected `i32`, found `()` (expected i32, found ())
```
We expected an integer, but we got `()`. `()` is pronounced *unit*, and is a
special type in Rust's type system. In Rust, `()` is _not_ a valid value for a
variable of type `i32`. It's only a valid value for variables of the type `()`,
which aren't very useful. Remember how we said statements don't return a value?
Well, that's the purpose of unit in this case. The semicolon turns any
expression into a statement by throwing away its value and returning unit
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`
This works because `if` is an expression. The value of the expression is the
value of the last expression in whichever branch was chosen. An `if` without an
`else` always results in `()` as the value.

View file

@ -1,27 +1,32 @@
% Installing Rust
The first step to using Rust is to install it! There are a number of ways to
install Rust, but the easiest is to use the `rustup` script. If you're on
Linux or a Mac, all you need to do is this (note that you don't need to type
in the `$`s, they just indicate the start of each command):
install Rust, but the easiest is to use the `rustup` script. If you're on Linux
or a Mac, all you need to do is this (note that you don't need to type in the
`$`s, they just indicate the start of each command):
```bash
$ curl -sf -L https://static.rust-lang.org/rustup.sh | sudo sh
```
If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`,
please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script:
If you're concerned about the [potential insecurity][insecurity] of using `curl
| sudo sh`, please keep reading and see our disclaimer below. And feel free to
use a two-step version of the installation and examine our installation script:
```bash
$ curl -f -L https://static.rust-lang.org/rustup.sh -O
$ sudo sh rustup.sh
```
If you're on Windows, please download either the [32-bit
installer](https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.exe)
or the [64-bit
installer](https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.exe)
and run it.
[insecurity]: http://curlpipesh.tumblr.com
If you're on Windows, please download either the [32-bit installer][win32] or
the [64-bit installer][win64] and run it.
[win32]: https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.msi
[win64]: https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.msi
## Uninstalling
If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay.
Not every programming language is great for everyone. Just run the uninstall
@ -31,22 +36,20 @@ script:
$ sudo /usr/local/lib/rustlib/uninstall.sh
```
If you used the Windows installer, just re-run the `.exe` and it will give you
If you used the Windows installer, just re-run the `.msi` and it will give you
an uninstall option.
You can re-run this script any time you want to update Rust. Which, at this
point, is often. Rust is still pre-1.0, and so people assume that you're using
a very recent Rust.
Some people, and somewhat rightfully so, get very upset when we tell you to
`curl | sudo sh`. Basically, when you do this, you are trusting that the good
people who maintain Rust aren't going to hack your computer and do bad things.
That's a good instinct! If you're one of those people, please check out the
documentation on [building Rust from Source][from source], or [the official
binary downloads][install page]. And we promise that this method will not be
the way to install Rust forever: it's just the easiest way to keep people
updated while Rust is in its alpha state.
This brings me to one other point: some people, and somewhat rightfully so, get
very upset when we tell you to `curl | sudo sh`. And they should be! Basically,
when you do this, you are trusting that the good people who maintain Rust
aren't going to hack your computer and do bad things. That's a good instinct!
If you're one of those people, please check out the documentation on [building
Rust from Source](https://github.com/rust-lang/rust#building-from-source), or
[the official binary downloads](http://www.rust-lang.org/install.html). And we
promise that this method will not be the way to install Rust forever: it's just
the easiest way to keep people updated while Rust is in its alpha state.
[from source]: https://github.com/rust-lang/rust#building-from-source
[install page]: http://www.rust-lang.org/install.html
Oh, we should also mention the officially supported platforms:
@ -73,7 +76,7 @@ $ rustc --version
You should see the version number, commit hash, commit date and build date:
```bash
rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06)
rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02)
```
If you did, Rust has been installed successfully! Congrats!
@ -84,10 +87,13 @@ On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
to.
If not, there are a number of places where you can get help. The easiest is
[the #rust IRC channel on irc.mozilla.org](irc://irc.mozilla.org/#rust), which
you can access through
[Mibbit](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust). Click
that link, and you'll be chatting with other Rustaceans (a silly nickname we
call ourselves), and we can help you out. Other great resources include [the
/r/rust subreddit](http://www.reddit.com/r/rust), and [Stack
Overflow](http://stackoverflow.com/questions/tagged/rust).
[the #rust IRC channel on irc.mozilla.org][irc], which you can access through
[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans
(a silly nickname we call ourselves), and we can help you out. Other great
resources include [the users forum][users], and [Stack Overflow][stack
overflow].
[irc]: irc://irc.mozilla.org/#rust
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
[users]: http://users.rust-lang.org/
[stack overflow]: http://stackoverflow.com/questions/tagged/rust

View file

@ -1 +1,4 @@
% Learn Rust
This section is coming soon! It will eventually have a few tutorials with
building real Rust projects, but they are under development.

View file

@ -1,13 +1,13 @@
% Match
Often, a simple `if`/`else` isn't enough, because you have more than two
Often, a simple `if`/`else` isnt enough, because you have more than two
possible options. Also, `else` conditions can get incredibly complicated, so
what's the solution?
whats the solution?
Rust has a keyword, `match`, that allows you to replace complicated `if`/`else`
groupings with something more powerful. Check it out:
```{rust}
```rust
let x = 5;
match x {
@ -21,11 +21,14 @@ match x {
```
`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.
the branch is of the form `val => expression`. When the value matches, that arms
expression will be evaluated. Its called `match` because of the term pattern
matching, which `match` is an implementation of. Theres an [entire section on
patterns][patterns] coming up next, that covers all the options that fit here.
So what's the big advantage here? Well, there are a few. First of all, `match`
[patterns]: patterns.html
So whats 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
underscore (`_`)? If we remove that arm, Rust will give us an error:
@ -36,121 +39,24 @@ 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,
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.
`match` statements also destructure enums, as well. Remember this code from the
section on enums?
```{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);
if ordering == Ordering::Less {
println!("less");
} else if ordering == Ordering::Greater {
println!("greater");
} else if ordering == Ordering::Equal {
println!("equal");
}
}
```
We can re-write this as a `match`:
```{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;
match cmp(x, y) {
Ordering::Less => println!("less"),
Ordering::Greater => println!("greater"),
Ordering::Equal => println!("equal"),
}
}
```
This version has way less noise, and it also checks exhaustively to make sure
that we have covered all possible variants of `Ordering`. With our `if`/`else`
version, if we had forgotten the `Greater` case, for example, our program would
have happily compiled. If we forget in the `match`, it will not. Rust helps us
make sure to cover all of our bases.
`match` expressions also allow us to get the values contained in an `enum`
(also known as destructuring) as follows:
```{rust}
enum OptionalInt {
Value(i32),
Missing,
}
fn main() {
let x = OptionalInt::Value(5);
let y = OptionalInt::Missing;
match x {
OptionalInt::Value(n) => println!("x is {}", n),
OptionalInt::Missing => println!("x is missing!"),
}
match y {
OptionalInt::Value(n) => println!("y is {}", n),
OptionalInt::Missing => println!("y is missing!"),
}
}
```
That is how you can get and use the values contained in `enum`s.
It can also allow us to handle errors or unexpected computations; for example, a
function that is not guaranteed to be able to compute a result (an `i32` here)
could return an `OptionalInt`, and we would handle that value with a `match`.
As you can see, `enum` and `match` used together are quite useful!
`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. We could
also implement the previous example like this:
side of a `let` binding or directly where an expression is used:
```{rust}
use std::cmp::Ordering;
```rust
let x = 5;
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;
println!("{}", match cmp(x, y) {
Ordering::Less => "less",
Ordering::Greater => "greater",
Ordering::Equal => "equal",
});
}
let numer = match x {
1 => "one",
2 => "two",
3 => "three",
4 => "four",
5 => "five",
_ => "something else",
};
```
Sometimes, it's a nice pattern.
Sometimes, its a nice way of converting things.

View file

@ -4,7 +4,7 @@ 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}
baz(bar(foo(x)));
baz(bar(foo)));
```
We would read this left-to right, and so we see "baz bar foo." But this isn't the
@ -12,7 +12,7 @@ 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}
x.foo().bar().baz();
foo.bar().baz();
```
Luckily, as you may have guessed with the leading question, you can! Rust provides
@ -47,8 +47,8 @@ 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 `x` in `x.foo()`. The three
variants correspond to the three kinds of thing `x` could be: `self` if it's
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

View file

@ -2,7 +2,9 @@
Rust provides three distribution channels for Rust: nightly, beta, and stable.
Unstable features are only available on nightly Rust. For more details on this
process, see [this post](http://blog.rust-lang.org/2014/10/30/Stability.html).
process, see [Stability as a deliverable][stability].
[stability]: http://blog.rust-lang.org/2014/10/30/Stability.html
To install nightly Rust, you can use `rustup.sh`:
@ -10,19 +12,24 @@ To install nightly Rust, you can use `rustup.sh`:
$ curl -s https://static.rust-lang.org/rustup.sh | sudo sh -s -- --channel=nightly
```
If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`,
please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script:
If you're concerned about the [potential insecurity][insecurity] of using `curl
| sudo sh`, please keep reading and see our disclaimer below. And feel free to
use a two-step version of the installation and examine our installation script:
```bash
$ curl -f -L https://static.rust-lang.org/rustup.sh -O
$ sudo sh rustup.sh --channel=nightly
$ sudo sh rustup.sh
```
If you're on Windows, please download either the [32-bit
installer](https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe)
or the [64-bit
installer](https://static.rust-lang.org/dist/rust-nightly-x86_64-pc-windows-gnu.exe)
and run it.
[insecurity]: http://curlpipesh.tumblr.com
If you're on Windows, please download either the [32-bit installer][win32] or
the [64-bit installer][win64] and run it.
[win32]: https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.msi
[win64]: https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.msi
## Uninstalling
If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay.
Not every programming language is great for everyone. Just run the uninstall
@ -32,20 +39,64 @@ script:
$ sudo /usr/local/lib/rustlib/uninstall.sh
```
If you used the Windows installer, just re-run the `.exe` and it will give you
If you used the Windows installer, just re-run the `.msi` and it will give you
an uninstall option.
You can re-run this script any time you want to update Rust. Which, at this
point, is often. Rust is still pre-1.0, and so people assume that you're using
a very recent Rust.
Some people, and somewhat rightfully so, get very upset when we tell you to
`curl | sudo sh`. Basically, when you do this, you are trusting that the good
people who maintain Rust aren't going to hack your computer and do bad things.
That's a good instinct! If you're one of those people, please check out the
documentation on [building Rust from Source][from source], or [the official
binary downloads][install page]. And we promise that this method will not be
the way to install Rust forever: it's just the easiest way to keep people
updated while Rust is in its alpha state.
This brings me to one other point: some people, and somewhat rightfully so, get
very upset when we tell you to `curl | sudo sh`. And they should be! Basically,
when you do this, you are trusting that the good people who maintain Rust
aren't going to hack your computer and do bad things. That's a good instinct!
If you're one of those people, please check out the documentation on [building
Rust from Source](https://github.com/rust-lang/rust#building-from-source), or
[the official binary downloads](http://www.rust-lang.org/install.html). And we
promise that this method will not be the way to install Rust forever: it's just
the easiest way to keep people updated while Rust is in its alpha state.
[from source]: https://github.com/rust-lang/rust#building-from-source
[install page]: http://www.rust-lang.org/install.html
Oh, we should also mention the officially supported platforms:
* Windows (7, 8, Server 2008 R2)
* Linux (2.6.18 or later, various distributions), x86 and x86-64
* OSX 10.7 (Lion) or greater, x86 and x86-64
We extensively test Rust on these platforms, and a few others, too, like
Android. But these are the ones most likely to work, as they have the most
testing.
Finally, a comment about Windows. Rust considers Windows to be a first-class
platform upon release, but if we're honest, the Windows experience isn't as
integrated as the Linux/OS X experience is. We're working on it! If anything
does not work, it is a bug. Please let us know if that happens. Each and every
commit is tested against Windows just like any other platform.
If you've got Rust installed, you can open up a shell, and type this:
```bash
$ rustc --version
```
You should see the version number, commit hash, commit date and build date:
```bash
rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06)
```
If you did, Rust has been installed successfully! Congrats!
This installer also installs a copy of the documentation locally, so you can
read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
to.
If not, there are a number of places where you can get help. The easiest is
[the #rust IRC channel on irc.mozilla.org][irc], which you can access through
[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans
(a silly nickname we call ourselves), and we can help you out. Other great
resources include [the users forum][users], and [Stack Overflow][stack
overflow].
[irc]: irc://irc.mozilla.org/#rust
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
[users]: http://users.rust-lang.org/
[stack overflow]: http://stackoverflow.com/questions/tagged/rust

View file

@ -1,13 +1,16 @@
% Patterns
We've made use of patterns a few times in the guide: first with `let` bindings,
then with `match` statements. Let's go on a whirlwind tour of all of the things
patterns can do!
Patterns are quite common in Rust. We use them in [variable
bindings][bindings], [match statements][match], and other places, too. Lets go
on a whirlwind tour of all of the things patterns can do!
[bindings]: variable-bindings.html
[match]: match.html
A quick refresher: you can match against literals directly, and `_` acts as an
*any* case:
any case:
```{rust}
```rust
let x = 1;
match x {
@ -18,9 +21,11 @@ match x {
}
```
# Multiple patterns
You can match multiple patterns with `|`:
```{rust}
```rust
let x = 1;
match x {
@ -30,9 +35,11 @@ match x {
}
```
# Ranges
You can match a range of values with `...`:
```{rust}
```rust
let x = 1;
match x {
@ -43,10 +50,12 @@ match x {
Ranges are mostly used with integers and single characters.
If you're matching multiple things, via a `|` or a `...`, you can bind
# Bindings
If youre matching multiple things, via a `|` or a `...`, you can bind
the value to a name with `@`:
```{rust}
```rust
let x = 1;
match x {
@ -55,10 +64,12 @@ match x {
}
```
If you're matching on an enum which has variants, you can use `..` to
# Ignoring variants
If youre matching on an enum which has variants, you can use `..` to
ignore the value and type in the variant:
```{rust}
```rust
enum OptionalInt {
Value(i32),
Missing,
@ -72,9 +83,11 @@ match x {
}
```
You can introduce *match guards* with `if`:
# Guards
```{rust}
You can introduce match guards with `if`:
```rust
enum OptionalInt {
Value(i32),
Missing,
@ -89,24 +102,11 @@ match x {
}
```
If you're matching on a pointer, you can use the same syntax as you declared it
with. First, `&`:
# ref and ref mut
```{rust}
let x = &5;
If you want to get a [reference][ref], use the `ref` keyword:
match x {
&val => println!("Got a value: {}", val),
}
```
Here, the `val` inside the `match` has type `i32`. In other words, the left-hand
side of the pattern destructures the value. If we have `&5`, then in `&val`, `val`
would be `5`.
If you want to get a reference, use the `ref` keyword:
```{rust}
```rust
let x = 5;
match x {
@ -114,11 +114,13 @@ match x {
}
```
[ref]: references-and-borrowing.html
Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref`
keyword _creates_ a reference, for use in the pattern. If you need a mutable
reference, `ref mut` will work in the same way:
```{rust}
```rust
let mut x = 5;
match x {
@ -126,10 +128,12 @@ match x {
}
```
If you have a struct, you can destructure it inside of a pattern:
# Destructuring
```{rust}
# #![allow(non_shorthand_field_patterns)]
If you have a compound data type, like a `struct`, you can destructure it
inside of a pattern:
```rust
struct Point {
x: i32,
y: i32,
@ -142,10 +146,9 @@ match origin {
}
```
If we only care about some of the values, we don't have to give them all names:
If we only care about some of the values, we dont have to give them all names:
```{rust}
# #![allow(non_shorthand_field_patterns)]
```rust
struct Point {
x: i32,
y: i32,
@ -160,8 +163,7 @@ match origin {
You can do this kind of match on any member, not just the first:
```{rust}
# #![allow(non_shorthand_field_patterns)]
```rust
struct Point {
x: i32,
y: i32,
@ -174,22 +176,16 @@ match origin {
}
```
If you want to match against a slice or array, you can use `&`:
This destructuring behavior works on any compound data type, like
[tuples][tuples] or [enums][enums].
```{rust}
# #![feature(slice_patterns)]
fn main() {
let v = vec!["match_this", "1"];
[tuples]: primitive-types.html#tuples
[enums]: enums.html
match &v[..] {
["match_this", second] => println!("The second element is {}", second),
_ => {},
}
}
```
# Mix and Match
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:
Whew! Thats a lot of different ways to match things, and they can all be
mixed and matched, depending on what youre doing:
```{rust,ignore}
match x {

View file

@ -1,3 +1,268 @@
% Primitive Types
Coming Soon!
The Rust language has a number of types that are considered primitive. This
means that theyre built-in to the language. Rust is structured in such a way
that the standard library also provides a number of useful types built on top
of these ones, as well, but these are the most primitive.
# Booleans
Rust has a built in boolean type, named `bool`. It has two values, `true` and `false`:
```rust
let x = true;
let y: bool = false;
```
A common use of booleans is in [`if` statements][if].
[if]: if.html
You can find more documentation for `bool`s [in the standard library
documentation][bool].
[bool]: ../std/primitive.bool.html
# `char`
The `char` type represents a single Unicode scalar value. You can create `char`s
with a single tick: (`'`)
```rust
let x = 'x';
let two_hearts = '💕';
```
Unlike some other languages, this means that Rusts `char` is not a single byte,
but four.
You can find more documentation for `char`s [in the standard library
documentation][char].
[char]: ../std/primitive.char.html
# Numeric types
Rust has a variety of numeric types in a few categories: signed and unsigned,
fixed and variable, floating-point and integer.
These types consist of two parts: the category, and the size. For example,
`u16` is an unsigned type with sixteen bits of size. More bits lets you have
bigger numbers.
If a number literal has nothing to cause its type to be inferred, it defaults:
```rust
let x = 42; // x has type i32
let y = 1.0; // y has type f64
```
Heres a list of the different numeric types, with links to their documentation
in the standard library:
* [i16](../std/primitive.i16.html)
* [i32](../std/primitive.i32.html)
* [i64](../std/primitive.i64.html)
* [i8](../std/primitive.i8.html)
* [u16](../std/primitive.u16.html)
* [u32](../std/primitive.u32.html)
* [u64](../std/primitive.u64.html)
* [u8](../std/primitive.u8.html)
* [isize](../std/primitive.isize.html)
* [usize](../std/primitive.usize.html)
* [f32](../std/primitive.f32.html)
* [f64](../std/primitive.f64.html)
Lets go over them by category:
## Signed and Unsigned
Integer types come in two varieties: signed and unsigned. To understand the
difference, lets consider a number with four bits of size. A signed, four-bit
number would let you store numbers from `-8` to `+7`. Signed numbers use
twos compliment representation. An unsigned four bit number, since it does
not need to store negatives, can store values from `0` to `+15`.
Unsigned types use a `u` for their category, and signed types use `i`. The `i`
is for integer. So `u8` is an eight-bit unsigned number, and `i8` is an
eight-bit signed number.
## Fixed size types
Fixed size types have a specific number of bits in their representation. Valid
bit sizes are `8`, `16`, `32`, and `64`. So, `u32` is an unsigned, 32-bit integer,
and `i64` is a signed, 64-bit integer.
## Variable sized types
Rust also provides types whose size depends on the size of a pointer of the
underlying machine. These types have size as the category, and come in signed
and unsigned varieties. This makes for two types: `isize` and `usize`.
## Floating-point types
Rust also two floating point types: `f32` and `f64`. These correspond to
IEEE-754 single and double precision numbers.
# 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]; // m: [i32; 3]
```
Arrays have type `[T; N]`. Well talk about this `T` notation [in the generics
section][generics]. The `N` is a compile-time constant, for the length of the
array.
Theres 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]
```
You can get the number of elements in an array `a` with `a.len()`:
```rust
let a = [1, 2, 3];
println!("a has {} elements", a.len());
```
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.
You can find more documentation for `array`s [in the standard library
documentation][array].
[array]: ../std/primitive.array.html
# Slices
A slice is a reference to (or “view” into) another data structure. 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
```
Slices have type `&[T]`. Well talk about that `T` when we cover
[generics][generics].
[generics]: generics.html
You can find more documentation for `slices`s [in the standard library
documentation][slice].
[slice]: ../std/primitive.slice.html
# `str`
Rusts `str` type is the most primitive string type. As an [unsized type][dst],
its not very useful by itself, but becomes useful when placed behind a reference,
like [`&str`][strings]. As such, well just leave it at that.
[dst]: unsized-types.html
[strings]: strings.html
You can find more documentation for `str` [in the standard library
documentation][str].
[str]: ../std/primitive.str.html
# Tuples
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. Heres 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.
In systems programming languages, strings are a bit more complex than in other
languages. For now, just read `&str` as a *string slice*, and well learn more
soon.
You can access the fields in a tuple through a *destructuring let*. Heres
an example:
```rust
let (x, y, z) = (1, 2, 3);
println!("x is {}", x);
```
Remember [before][let] 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.
[let]: variable-bindings.html
This pattern is very powerful, and well 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.
[arity]: glossary.html#arity
```rust
let mut x = (1, 2); // x: (i32, i32)
let y = (2, 3); // y: (i32, i32)
x = y;
```
You can find more documentation for tuples [in the standard library
documentation][tuple].
[tuple]: ../std/primitive.tuple.html
# Functions
Functions also have a type! They look like this:
```
fn foo(x: i32) -> i32 { x }
let x: fn(i32) -> i32 = foo;
```
In this case, `x` is a function pointer to a function that takes an `i32` and
returns an `i32`.

View file

@ -0,0 +1,18 @@
% Slice patterns
If you want to match against a slice or array, you can use `&` with the
`slice_patterns` feature:
```rust
#![feature(slice_patterns)]
fn main() {
let v = vec!["match_this", "1"];
match &v[..] {
["match_this", second] => println!("The second element is {}", second),
_ => {},
}
}
```

View file

@ -1,21 +0,0 @@
% 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.

View file

@ -1 +1,10 @@
% Syntax and Semantics
This section breaks Rust down into small chunks, one for each concept.
If youd like to learn Rust from the bottom up, reading this in order is a
great way to do that.
These sections also form a reference for each concept, so if youre reading
another tutorial and find something confusing, you can find it explained
somewhere in here.

View file

@ -1,97 +0,0 @@
% 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.

View file

@ -1,44 +1,48 @@
% Variable Bindings
The first thing we'll learn about are *variable bindings*. They look like this:
Vitually every non-Hello World Rust program uses *variable bindings*. They
look like this:
```{rust}
```rust
fn main() {
let x = 5;
}
```
Putting `fn main() {` in each example is a bit tedious, so we'll leave that out
in the future. If you're following along, make sure to edit your `main()`
function, rather than leaving it off. Otherwise, you'll get an error.
Putting `fn main() {` in each example is a bit tedious, so well leave that out
in the future. If youre following along, make sure to edit your `main()`
function, rather than leaving it off. Otherwise, youll get an error.
In many languages, this is called a *variable*. But Rust's variable bindings
have a few tricks up their sleeves. Rust has a very powerful feature called
*pattern matching* that we'll get into detail with later, but the left
hand side of a `let` expression is a full pattern, not just a variable name.
This means we can do things like:
In many languages, this is called a *variable*, but Rusts variable bindings
have a few tricks up their sleeves. For example the left-hand side of a `let`
expression is a [pattern][pattern], not just a variable name. This means we
can do things like:
```{rust}
```rust
let (x, y) = (1, 2);
```
After this expression is evaluated, `x` will be one, and `y` will be two.
Patterns are really powerful, but this is about all we can do with them so far.
So let's just keep this in the back of our minds as we go forward.
Patterns are really powerful, and have [their own section][pattern] in the
book. We dont need those features for now, so well just keep this in the back
of our minds as we go forward.
[pattern]: patterns.html
Rust is a statically typed language, which means that we specify our types up
front. So why does our first example compile? Well, Rust has this thing called
*type inference*. If it can figure out what the type of something is, Rust
doesn't require you to actually type it out.
front, and theyre checked at compile time. So why does our first example
compile? Well, Rust has this thing called type inference. If it can figure
out what the type of something is, Rust doesnt require you to actually type it
out.
We can add the type if we want to, though. Types come after a colon (`:`):
```{rust}
```rust
let x: i32 = 5;
```
If I asked you to read this out loud to the rest of the class, you'd say "`x`
is a binding with the type `i32` and the value `five`."
If I asked you to read this out loud to the rest of the class, youd say “`x`
is a binding with the type `i32` and the value `five`.
In this case we chose to represent `x` as a 32-bit signed integer. Rust has
many different primitive integer types. They begin with `i` for signed integers
@ -48,19 +52,20 @@ bits.
In future examples, we may annotate the type in a comment. The examples will
look like this:
```{rust}
```rust
fn main() {
let x = 5; // x: i32
}
```
Note the similarities between this annotation and the syntax you use with `let`.
Including these kinds of comments is not idiomatic Rust, but we'll occasionally
include them to help you understand what the types that Rust infers are.
Note the similarities between this annotation and the syntax you use with
`let`. Including these kinds of comments is not idiomatic Rust, but we'll
occasionally include them to help you understand what the types that Rust
infers are.
By default, bindings are *immutable*. This code will not compile:
```{ignore}
```rust,ignore
let x = 5;
x = 10;
```
@ -75,30 +80,30 @@ error: re-assignment of immutable variable `x`
If you want a binding to be mutable, you can use `mut`:
```{rust}
```rust
let mut x = 5; // mut x: i32
x = 10;
```
There is no single reason that bindings are immutable by default, but we can
think about it through one of Rust's primary focuses: safety. If you forget to
think about it through one of Rusts primary focuses: safety. If you forget to
say `mut`, the compiler will catch it, and let you know that you have mutated
something you may not have intended to mutate. If bindings were mutable by
default, the compiler would not be able to tell you this. If you _did_ intend
mutation, then the solution is quite easy: add `mut`.
There are other good reasons to avoid mutable state when possible, but they're
There are other good reasons to avoid mutable state when possible, but theyre
out of the scope of this guide. In general, you can often avoid explicit
mutation, and so it is preferable in Rust. That said, sometimes, mutation is
what you need, so it's not verboten.
what you need, so its not verboten.
Let's get back to bindings. Rust variable bindings have one more aspect that
Lets get back to bindings. Rust variable bindings have one more aspect that
differs from other languages: bindings are required to be initialized with a
value before you're allowed to use them.
Let's try it out. Change your `src/main.rs` file to look like this:
Lets try it out. Change your `src/main.rs` file to look like this:
```{rust}
```rust
fn main() {
let x: i32;
@ -106,21 +111,22 @@ fn main() {
}
```
You can use `cargo build` on the command line to build it. You'll get a warning,
but it will still print "Hello, world!":
You can use `cargo build` on the command line to build it. Youll get a
warning, but it will still print "Hello, world!":
```text
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)]
on by default
src/main.rs:2 let x: i32;
^
```
Rust warns us that we never use the variable binding, but since we never use it,
no harm, no foul. Things change if we try to actually use this `x`, however. Let's
do that. Change your program to look like this:
Rust warns us that we never use the variable binding, but since we never use
it, no harm, no foul. Things change if we try to actually use this `x`,
however. Lets do that. Change your program to look like this:
```{rust,ignore}
```rust,ignore
fn main() {
let x: i32;
@ -128,9 +134,9 @@ fn main() {
}
```
And try to build it. You'll get an error:
And try to build it. Youll get an error:
```{bash}
```bash
$ cargo build
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x`
@ -144,18 +150,20 @@ error: aborting due to previous error
Could not compile `hello_world`.
```
Rust will not let us use a value that has not been initialized. Next, let's
Rust will not let us use a value that has not been initialized. Next, lets
talk about this stuff we've added to `println!`.
If you include two curly braces (`{}`, some call them moustaches...) in your
string to print, Rust will interpret this as a request to interpolate some sort
of value. *String interpolation* is a computer science term that means "stick
in the middle of a string." We add a comma, and then `x`, to indicate that we
want `x` to be the value we're interpolating. The comma is used to separate
arguments we pass to functions and macros, if you're passing more than one.
want `x` to be the value were interpolating. The comma is used to separate
arguments we pass to functions and macros, if youre passing more than one.
When you just use the curly braces, Rust will attempt to display the
value in a meaningful way by checking out its type. If you want to specify the
format in a more detailed manner, there are a [wide number of options
available](../std/fmt/index.html). For now, we'll just stick to the default:
integers aren't very complicated to print.
When you just use the curly braces, Rust will attempt to display the value in a
meaningful way by checking out its type. If you want to specify the format in a
more detailed manner, there are a [wide number of options available][format].
For now, we'll just stick to the default: integers aren't very complicated to
print.
[format]: ../std/fmt/index.html

View file

@ -1,7 +1,6 @@
% `while` loops
% while loops
The other kind of looping construct in Rust is the `while` loop. It looks like
this:
Rust also has a `while` loop. It looks like this:
```{rust}
let mut x = 5; // mut x: u32
@ -9,45 +8,52 @@ let mut done = false; // mut done: bool
while !done {
x += x - 3;
println!("{}", x);
if x % 5 == 0 { done = true; }
if x % 5 == 0 {
done = true;
}
}
```
`while` loops are the correct choice when you're not sure how many times
`while` loops are the correct choice when youre not sure how many times
you need to loop.
If you need an infinite loop, you may be tempted to write this:
```{rust,ignore}
```rust,ignore
while true {
```
However, Rust has a dedicated keyword, `loop`, to handle this case:
```{rust,ignore}
```rust,ignore
loop {
```
Rust's control-flow analysis treats this construct differently than a
`while true`, since we know that it will always loop. The details of what
that _means_ aren't super important to understand at this stage, but in
general, the more information we can give to the compiler, the better it
can do with safety and code generation, so you should always prefer
`loop` when you plan to loop infinitely.
Rusts control-flow analysis treats this construct differently than a `while
true`, since we know that it will always loop. In general, the more information
we can give to the compiler, the better it can do with safety and code
generation, so you should always prefer `loop` when you plan to loop
infinitely.
## Ending iteration early
Let's take a look at that `while` loop we had earlier:
Lets take a look at that `while` loop we had earlier:
```{rust}
```rust
let mut x = 5;
let mut done = false;
while !done {
x += x - 3;
println!("{}", x);
if x % 5 == 0 { done = true; }
if x % 5 == 0 {
done = true;
}
}
```
@ -57,12 +63,14 @@ modifying iteration: `break` and `continue`.
In this case, we can write the loop in a better way with `break`:
```{rust}
```rust
let mut x = 5;
loop {
x += x - 3;
println!("{}", x);
if x % 5 == 0 { break; }
}
```
@ -72,7 +80,7 @@ We now loop forever with `loop` and use `break` to break out early.
`continue` is similar, but instead of ending the loop, goes to the next
iteration. This will only print the odd numbers:
```{rust}
```rust
for x in 0..10 {
if x % 2 == 0 { continue; }
@ -80,4 +88,6 @@ for x in 0..10 {
}
```
Both `continue` and `break` are valid in both kinds of loops.
Both `continue` and `break` are valid in both `while` loops and [`for` loops][for].
[for]: for-loops.html

View file

@ -1,615 +0,0 @@
#!/bin/sh
# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
msg() {
echo "rustup: $1"
}
step_msg() {
msg
msg "$1"
msg
}
warn() {
echo "rustup: WARNING: $1"
}
err() {
echo "rustup: error: $1"
exit 1
}
need_ok() {
if [ $? -ne 0 ]
then
err "$1"
fi
}
putvar() {
local T
eval T=\$$1
eval TLEN=\${#$1}
if [ $TLEN -gt 35 ]
then
printf "rustup: %-20s := %.35s ...\n" $1 "$T"
else
printf "rustup: %-20s := %s %s\n" $1 "$T" "$2"
fi
}
probe() {
local V=$1
shift
local P
local T
for P
do
T=$(which $P 2>&1)
if [ $? -eq 0 ]
then
VER0=$($P --version 2>/dev/null | head -1 \
| sed -e 's/[^0-9]*\([vV]\?[0-9.]\+[^ ]*\).*/\1/' )
if [ $? -eq 0 -a "x${VER0}" != "x" ]
then
VER="($VER0)"
else
VER=""
fi
break
else
VER=""
T=""
fi
done
eval $V=\$T
putvar $V "$VER"
}
probe_need() {
local V=$1
probe $*
eval VV=\$$V
if [ -z "$VV" ]
then
err "needed, but unable to find any of: $*"
fi
}
valopt() {
VAL_OPTIONS="$VAL_OPTIONS $1"
local OP=$1
local DEFAULT=$2
shift
shift
local DOC="$*"
if [ $HELP -eq 0 ]
then
local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
local V="CFG_${UOP}"
eval $V="$DEFAULT"
for arg in $CFG_ARGS
do
if echo "$arg" | grep -q -- "--$OP="
then
val=$(echo "$arg" | cut -f2 -d=)
eval $V=$val
fi
done
putvar $V
else
if [ -z "$DEFAULT" ]
then
DEFAULT="<none>"
fi
OP="${OP}=[${DEFAULT}]"
printf " --%-30s %s\n" "$OP" "$DOC"
fi
}
opt() {
BOOL_OPTIONS="$BOOL_OPTIONS $1"
local OP=$1
local DEFAULT=$2
shift
shift
local DOC="$*"
local FLAG=""
if [ $DEFAULT -eq 0 ]
then
FLAG="enable"
else
FLAG="disable"
DOC="don't $DOC"
fi
if [ $HELP -eq 0 ]
then
for arg in $CFG_ARGS
do
if [ "$arg" = "--${FLAG}-${OP}" ]
then
OP=$(echo $OP | tr 'a-z-' 'A-Z_')
FLAG=$(echo $FLAG | tr 'a-z' 'A-Z')
local V="CFG_${FLAG}_${OP}"
eval $V=1
putvar $V
fi
done
else
if [ ! -z "$META" ]
then
OP="$OP=<$META>"
fi
printf " --%-30s %s\n" "$FLAG-$OP" "$DOC"
fi
}
flag() {
BOOL_OPTIONS="$BOOL_OPTIONS $1"
local OP=$1
shift
local DOC="$*"
if [ $HELP -eq 0 ]
then
for arg in $CFG_ARGS
do
if [ "$arg" = "--${OP}" ]
then
OP=$(echo $OP | tr 'a-z-' 'A-Z_')
local V="CFG_${OP}"
eval $V=1
putvar $V
fi
done
else
if [ ! -z "$META" ]
then
OP="$OP=<$META>"
fi
printf " --%-30s %s\n" "$OP" "$DOC"
fi
}
validate_opt() {
for arg in $CFG_ARGS
do
isArgValid=0
for option in $BOOL_OPTIONS
do
if test --disable-$option = $arg
then
isArgValid=1
fi
if test --enable-$option = $arg
then
isArgValid=1
fi
if test --$option = $arg
then
isArgValid=1
fi
done
for option in $VAL_OPTIONS
do
if echo "$arg" | grep -q -- "--$option="
then
isArgValid=1
fi
done
if [ "$arg" = "--help" ]
then
echo
echo "No more help available for Configure options,"
echo "check the Wiki or join our IRC channel"
break
else
if test $isArgValid -eq 0
then
err "Option '$arg' is not recognized"
fi
fi
done
}
create_tmp_dir() {
local TMP_DIR=`pwd`/rustup-tmp-install
rm -Rf "${TMP_DIR}"
need_ok "failed to remove temporary installation directory"
mkdir -p "${TMP_DIR}"
need_ok "failed to create create temporary installation directory"
echo $TMP_DIR
}
# Make `tr` locale independent
LC_CTYPE=C
probe_need CFG_CURL curl
probe_need CFG_TAR tar
probe_need CFG_FILE file
probe CFG_SHA256SUM sha256sum
probe CFG_SHASUM shasum
if [ -z "$CFG_SHA256SUM" -a -z "$CFG_SHASUM" ]; then
err "unable to find either sha256sum or shasum"
fi
calculate_hash() {
if [ -n "$CFG_SHA256SUM" ]; then
${CFG_SHA256SUM} $@
else
${CFG_SHASUM} -a 256 $@
fi
}
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
CFG_SELF="$0"
CFG_ARGS="$@"
HELP=0
if [ "$1" = "--help" ]
then
HELP=1
shift
echo
echo "Usage: $CFG_SELF [options]"
echo
echo "Options:"
echo
else
step_msg "processing $CFG_SELF args"
fi
OPTIONS=""
BOOL_OPTIONS=""
VAL_OPTIONS=""
flag uninstall "only uninstall from the installation prefix"
valopt prefix "${RUSTUP_PREFIX}" "set installation prefix"
valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly"
valopt channel "beta" "use the selected release channel [beta]"
flag save "save the downloaded nightlies to ~/.rustup"
if [ $HELP -eq 1 ]
then
echo
exit 0
fi
step_msg "validating $CFG_SELF args"
validate_opt
# Platform detection copied from `configure`
CFG_OSTYPE=$(uname -s)
CFG_CPUTYPE=$(uname -m)
if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ]
then
# Darwin's `uname -m` lies and always returns i386. We have to use sysctl
# instead.
if sysctl hw.optional.x86_64 | grep -q ': 1'
then
CFG_CPUTYPE=x86_64
fi
fi
# The goal here is to come up with the same triple as LLVM would,
# at least for the subset of platforms we're willing to target.
case $CFG_OSTYPE in
Linux)
CFG_OSTYPE=unknown-linux-gnu
;;
FreeBSD)
CFG_OSTYPE=unknown-freebsd
;;
Darwin)
CFG_OSTYPE=apple-darwin
;;
MINGW32*)
CFG_OSTYPE=pc-mingw32
;;
# Thad's Cygwin identifiers below
# Vista 32 bit
CYGWIN_NT-6.0)
CFG_OSTYPE=pc-mingw32
CFG_CPUTYPE=i686
;;
# Vista 64 bit
CYGWIN_NT-6.0-WOW64)
CFG_OSTYPE=w64-mingw32
CFG_CPUTYPE=x86_64
;;
# Win 7 32 bit
CYGWIN_NT-6.1)
CFG_OSTYPE=pc-mingw32
CFG_CPUTYPE=i686
;;
# Win 7 64 bit
CYGWIN_NT-6.1-WOW64)
CFG_OSTYPE=w64-mingw32
CFG_CPUTYPE=x86_64
;;
# We do not detect other OS such as XP/2003 using 64 bit using uname.
# If we want to in the future, we will need to use Cygwin
# Chuck's csih helper in /usr/lib/csih/winProductName.exe or alternative.
*)
err "unknown OS type: $CFG_OSTYPE"
;;
esac
case $CFG_CPUTYPE in
i386 | i486 | i686 | i786 | x86)
CFG_CPUTYPE=i686
;;
xscale | arm)
CFG_CPUTYPE=arm
;;
x86_64 | x86-64 | x64 | amd64)
CFG_CPUTYPE=x86_64
;;
*)
err "unknown CPU type: $CFG_CPUTYPE"
esac
# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation
if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ]
then
"${CFG_FILE}" -L "$SHELL" | grep -q "x86[_-]64"
if [ $? != 0 ]; then
CFG_CPUTYPE=i686
fi
fi
HOST_TRIPLE="${CFG_CPUTYPE}-${CFG_OSTYPE}"
# Is this a triple we have nightlies for?
case $HOST_TRIPLE in
x86_64-unknown-linux-gnu)
;;
i686-unknown-linux-gnu)
;;
x86_64-apple-darwin)
;;
i686-apple-darwin)
;;
*)
err "rustup.sh doesn't work for host $HOST_TRIPLE"
esac
msg "host triple: ${HOST_TRIPLE}"
CFG_INSTALL_FLAGS=""
if [ -n "${CFG_UNINSTALL}" ]
then
CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --uninstall"
fi
if [ -n "${CFG_PREFIX}" ]
then
CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --prefix=${CFG_PREFIX}"
fi
CFG_TMP_DIR=$(mktemp -d 2>/dev/null \
|| mktemp -d -t 'rustup-tmp-install' 2>/dev/null \
|| create_tmp_dir)
# If we're saving nightlies and we didn't specify which one, grab the latest
# version from the perspective of the server. Buildbot has typically finished
# building and uploading by ~8UTC, but we want to include a little buffer.
#
# FIXME It would be better to use the known most recent nightly that has been
# built. This is waiting on a change to have buildbot publish metadata that
# can be queried.
if [ -n "${CFG_SAVE}" -a -z "${CFG_DATE}" ];
then
CFG_DATE=`TZ=Etc/UTC+9 date "+%Y-%m-%d"`
fi
RUST_URL="https://static.rust-lang.org/dist"
case "$CFG_CHANNEL" in
nightly)
# add a date suffix if we want a particular nightly.
if [ -n "${CFG_DATE}" ];
then
RUST_URL="${RUST_URL}/${CFG_DATE}"
fi
RUST_PACKAGE_NAME=rust-nightly
;;
beta)
RUST_PACKAGE_NAME=rust-1.0.0-beta
;;
*)
err "Currently 'beta' and 'nightly' are the only supported channels"
esac
RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}"
RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz"
RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}"
RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh"
download_hash() {
msg "Downloading ${remote_sha256}"
remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"`
if [ -n "${CFG_SAVE}" ]; then
echo "${remote_sha256}" > "${local_sha_file}"
fi
if [ "$?" -ne 0 ]; then
rm -Rf "${CFG_TMP_DIR}"
err "Failed to download ${remote_url}"
fi
}
verify_hash() {
remote_sha256="$1"
local_file="$2"
local_sha_file="${local_file}.sha256"
if [ -n "${CFG_SAVE}" ]; then
if [ -f "${local_sha_file}" ]; then
msg "Local ${local_sha_file} exists, treating as remote hash"
remote_sha256=`cat "${local_sha_file}"`
else
download_hash
fi
else
download_hash
fi
msg "Verifying hash"
local_sha256=$(calculate_hash "${local_file}")
if [ "$?" -ne 0 ]; then
rm -Rf "${CFG_TMP_DIR}"
err "Failed to compute hash for ${local_tarball}"
fi
# We only need the sha, not the filenames
remote_sha256=`echo ${remote_sha256} | cut -f 1 -d ' '`
local_sha256=`echo ${local_sha256} | cut -f 1 -d ' '`
if [ "${remote_sha256}" != "${local_sha256}" ]; then
rm -Rf "${CFG_TMP_DIR}"
errmsg="invalid sha256.\n"
errmsg="$errmsg ${remote_sha256}\t${remote_tarball}\n"
errmsg="$errmsg ${local_sha256}\t${local_tarball}"
err "$errmsg"
fi
}
# Fetch the package. Optionally caches the tarballs.
download_package() {
remote_tarball="$1"
local_tarball="$2"
remote_sha256="${remote_tarball}.sha256"
# Check if we've already downloaded this file.
if [ -e "${local_tarball}.tmp" ]; then
msg "Resuming ${remote_tarball} to ${local_tarball}"
"${CFG_CURL}" -f -C - -o "${local_tarball}.tmp" "${remote_tarball}"
if [ $? -ne 0 ]
then
rm -Rf "${CFG_TMP_DIR}"
err "failed to download installer"
fi
mv "${local_tarball}.tmp" "${local_tarball}"
elif [ ! -e "${local_tarball}" ]; then
msg "Downloading ${remote_tarball} to ${local_tarball}"
"${CFG_CURL}" -f -o "${local_tarball}.tmp" "${remote_tarball}"
if [ $? -ne 0 ]
then
rm -Rf "${CFG_TMP_DIR}"
err "failed to download installer"
fi
mv "${local_tarball}.tmp" "${local_tarball}"
fi
verify_hash "${remote_sha256}" "${local_tarball}"
}
# Wrap all the commands needed to install a package.
install_package() {
local_tarball="$1"
install_script="$2"
msg "Extracting ${local_tarball}"
(cd "${CFG_TMP_DIR}" && "${CFG_TAR}" -xzf "${local_tarball}")
if [ $? -ne 0 ]; then
rm -Rf "${CFG_TMP_DIR}"
err "failed to unpack installer"
fi
sh "${install_script}" "${CFG_INSTALL_FLAGS}"
if [ $? -ne 0 ]
then
rm -Rf "${CFG_TMP_DIR}"
err "failed to install Rust"
fi
}
# It's possible that curl could be interrupted partway though downloading
# `rustup.sh`, truncating the file. This could be especially bad if we were in
# the middle of a line that would run "rm -rf ". To protect against this, we
# wrap up the `rustup.sh` destructive functionality in this helper function,
# which we call as the last thing we do. This means we will not do anything
# unless we have the entire file downloaded.
install_packages() {
rm -Rf "${CFG_TMP_DIR}"
need_ok "failed to remove temporary installation directory"
mkdir -p "${CFG_TMP_DIR}"
need_ok "failed to create create temporary installation directory"
# If we're saving our nightlies, put them in $HOME/.rustup.
if [ -n "${CFG_SAVE}" ]
then
RUST_DOWNLOAD_DIR="${HOME}/.rustup/${CFG_DATE}"
else
RUST_DOWNLOAD_DIR="${CFG_TMP_DIR}"
fi
mkdir -p "${RUST_DOWNLOAD_DIR}"
need_ok "failed to create create download directory"
RUST_LOCAL_TARBALL="${RUST_DOWNLOAD_DIR}/${RUST_TARBALL_NAME}"
download_package \
"${RUST_URL}/${RUST_TARBALL_NAME}" \
"${RUST_LOCAL_TARBALL}"
install_package \
"${RUST_LOCAL_TARBALL}" \
"${RUST_LOCAL_INSTALL_SCRIPT}"
rm -Rf "${CFG_TMP_DIR}"
need_ok "couldn't rm temporary installation directory"
}
install_packages

View file

@ -362,10 +362,6 @@ fn test_arena_destructors_fail() {
}
/// A faster arena that can hold objects of only one type.
///
/// Safety note: Modifying objects in the arena that have already had their
/// `drop` destructors run can cause leaks, because the destructor will not
/// run again for these objects.
pub struct TypedArena<T> {
/// A pointer to the next object to be allocated.
ptr: Cell<*const T>,

View file

@ -39,7 +39,7 @@ use self::Cow::*;
/// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
/// Immutably borrow from an owned value.
/// Immutably borrows from an owned value.
///
/// # Examples
///
@ -67,7 +67,7 @@ pub trait Borrow<Borrowed: ?Sized> {
/// Similar to `Borrow`, but for mutable borrows.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BorrowMut<Borrowed: ?Sized> : Borrow<Borrowed> {
/// Mutably borrow from an owned value.
/// Mutably borrows from an owned value.
///
/// # Examples
///
@ -126,7 +126,7 @@ impl<'a, B: ?Sized> Borrow<B> for Cow<'a, B> where B: ToOwned, <B as ToOwned>::O
}
}
/// A generalization of Clone to borrowed data.
/// A generalization of `Clone` to borrowed data.
///
/// Some types make it possible to go from borrowed to owned, usually by
/// implementing the `Clone` trait. But `Clone` works only for going from `&T`
@ -137,7 +137,7 @@ pub trait ToOwned {
#[stable(feature = "rust1", since = "1.0.0")]
type Owned: Borrow<Self>;
/// Create owned data from borrowed data, usually by copying.
/// Creates owned data from borrowed data, usually by cloning.
#[stable(feature = "rust1", since = "1.0.0")]
fn to_owned(&self) -> Self::Owned;
}
@ -155,9 +155,9 @@ impl<T> ToOwned for T where T: Clone {
/// data lazily when mutation or ownership is required. The type is designed to
/// work with general borrowed data via the `Borrow` trait.
///
/// `Cow` implements both `Deref`, which means that you can call
/// `Cow` implements `Deref`, which means that you can call
/// non-mutating methods directly on the data it encloses. If mutation
/// is desired, `to_mut` will obtain a mutable references to an owned
/// is desired, `to_mut` will obtain a mutable reference to an owned
/// value, cloning if necessary.
///
/// # Examples
@ -200,7 +200,7 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned {
}
impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
/// Acquire a mutable reference to the owned form of the data.
/// Acquires a mutable reference to the owned form of the data.
///
/// Copies the data if it is not already owned.
///
@ -226,7 +226,7 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
}
}
/// Extract the owned data.
/// Extracts the owned data.
///
/// Copies the data if it is not already owned.
///
@ -327,7 +327,7 @@ impl<'a, B: ?Sized> Hash for Cow<'a, B> where B: Hash + ToOwned
}
}
/// Trait for moving into a `Cow`
/// Trait for moving into a `Cow`.
#[unstable(feature = "into_cow", reason = "may be replaced by `convert::Into`")]
pub trait IntoCow<'a, B: ?Sized> where B: ToOwned {
/// Moves `self` into `Cow`

View file

@ -313,7 +313,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
// 2) While ODS may potentially return the pair we *just* inserted after
// the split, we will never do this. Again, this shouldn't effect the analysis.
/// Inserts a key-value pair from the map. If the key already had a value
/// Inserts a key-value pair into the map. If the key already had a value
/// present in the map, that value is returned. Otherwise, `None` is returned.
///
/// # Examples

View file

@ -525,8 +525,7 @@ impl<T> Vec<T> {
///
/// # Panics
///
/// Panics if `index` is not between `0` and the vector's length (both
/// bounds inclusive).
/// Panics if `index` is greater than the vector's length.
///
/// # Examples
///

View file

@ -576,7 +576,7 @@ impl<V> VecMap<V> {
}
}
/// Inserts a key-value pair from the map. If the key already had a value
/// Inserts a key-value pair into the map. If the key already had a value
/// present in the map, that value is returned. Otherwise, `None` is returned.
///
/// # Examples

View file

@ -10,15 +10,35 @@
//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about
//! conversions from one type to another. They follow the standard
//! Rust conventions of `as`/`to`/`into`/`from`.
//! The traits in this module provide a general way to talk about conversions from one type to
//! another. They follow the standard Rust conventions of `as`/`to`/`into`/`from`.
//!
//! Like many traits, these are often used as bounds for generic functions, to support arguments of
//! multiple types.
//!
//! See each trait for usage examples.
#![stable(feature = "rust1", since = "1.0.0")]
use marker::Sized;
/// A cheap, reference-to-reference conversion.
///
/// # Examples
///
/// Both `String` and `&str` implement `AsRef<str>`:
///
/// ```
/// fn is_hello<T: AsRef<str>>(s: T) {
/// assert_eq!("hello", s.as_ref());
/// }
///
/// let s = "hello";
/// is_hello(s);
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
/// Performs the conversion.
@ -34,8 +54,21 @@ pub trait AsMut<T: ?Sized> {
fn as_mut(&mut self) -> &mut T;
}
/// A conversion that consumes `self`, which may or may not be
/// expensive.
/// A conversion that consumes `self`, which may or may not be expensive.
///
/// # Examples
///
/// `String` implements `Into<Vec<u8>>`:
///
/// ```
/// fn is_hello<T: Into<Vec<u8>>>(s: T) {
/// let bytes = b"hello".to_vec();
/// assert_eq!(bytes, s.into());
/// }
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
/// Performs the conversion.
@ -44,6 +77,19 @@ pub trait Into<T>: Sized {
}
/// Construct `Self` via a conversion.
///
/// # Examples
///
/// `String` implements `From<&str>`:
///
/// ```
/// let s = "hello";
/// let string = "hello".to_string();
///
/// let other_string: String = From::from(s);
///
/// assert_eq!(string, other_string);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
/// Performs the conversion.

View file

@ -217,7 +217,7 @@ pub trait Int
reason = "pending integer conventions")]
fn trailing_zeros(self) -> u32;
/// Shifts the bits to the left by a specified amount amount, `n`, wrapping
/// Shifts the bits to the left by a specified amount, `n`, wrapping
/// the truncated bits to the end of the resulting integer.
///
/// # Examples
@ -235,7 +235,7 @@ pub trait Int
reason = "pending integer conventions")]
fn rotate_left(self, n: u32) -> Self;
/// Shifts the bits to the right by a specified amount amount, `n`, wrapping
/// Shifts the bits to the right by a specified amount, `n`, wrapping
/// the truncated bits to the beginning of the resulting integer.
///
/// # Examples
@ -856,9 +856,8 @@ macro_rules! int_impl {
///
/// # Return value
///
/// `None` if the string did not represent a valid number.
/// Otherwise, `Some(n)` where `n` is the integer represented
/// by `src`.
/// `Err(ParseIntError)` if the string did not represent a valid number.
/// Otherwise, `Ok(n)` where `n` is the integer represented by `src`.
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
pub fn from_str_radix(src: &str, radix: u32) -> Result<$T, ParseIntError> {
@ -937,7 +936,7 @@ macro_rules! int_impl {
(self as $UnsignedT).trailing_zeros()
}
/// Shifts the bits to the left by a specified amount amount, `n`,
/// Shifts the bits to the left by a specified amount, `n`,
/// wrapping the truncated bits to the end of the resulting integer.
///
/// # Examples
@ -957,7 +956,7 @@ macro_rules! int_impl {
(self as $UnsignedT).rotate_left(n) as $T
}
/// Shifts the bits to the right by a specified amount amount, `n`,
/// Shifts the bits to the right by a specified amount, `n`,
/// wrapping the truncated bits to the beginning of the resulting
/// integer.
///
@ -1224,11 +1223,10 @@ macro_rules! int_impl {
///
/// # Examples
///
/// ```rust
/// # #![feature(core)]
/// use std::num::Int;
/// ```
/// let x: i32 = 2; // or any other integer type
///
/// assert_eq!(2.pow(4), 16);
/// assert_eq!(x.pow(4), 16);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@ -1374,9 +1372,8 @@ macro_rules! uint_impl {
///
/// # Return value
///
/// `None` if the string did not represent a valid number.
/// Otherwise, `Some(n)` where `n` is the integer represented
/// by `src`.
/// `Err(ParseIntError)` if the string did not represent a valid number.
/// Otherwise, `Ok(n)` where `n` is the integer represented by `src`.
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
pub fn from_str_radix(src: &str, radix: u32) -> Result<$T, ParseIntError> {
@ -1457,7 +1454,7 @@ macro_rules! uint_impl {
unsafe { $cttz(self as $ActualT) as u32 }
}
/// Shifts the bits to the left by a specified amount amount, `n`,
/// Shifts the bits to the left by a specified amount, `n`,
/// wrapping the truncated bits to the end of the resulting integer.
///
/// # Examples
@ -1479,7 +1476,7 @@ macro_rules! uint_impl {
(self << n) | (self >> (($BITS - n) % $BITS))
}
/// Shifts the bits to the right by a specified amount amount, `n`,
/// Shifts the bits to the right by a specified amount, `n`,
/// wrapping the truncated bits to the beginning of the resulting
/// integer.
///
@ -2708,8 +2705,8 @@ macro_rules! from_str_radix_float_impl {
///
/// # Return value
///
/// `None` if the string did not represent a valid number. Otherwise,
/// `Some(n)` where `n` is the floating-point number represented by `src`.
/// `Err(ParseIntError)` if the string did not represent a valid number. Otherwise,
/// Otherwise, `Ok(n)` where `n` is the floating-point number represented by `src`.
#[inline]
#[allow(deprecated)]
fn from_str(src: &str) -> Result<$T, ParseFloatError> {
@ -2737,9 +2734,8 @@ macro_rules! from_str_radix_float_impl {
///
/// # Return value
///
/// `None` if the string did not represent a valid number.
/// Otherwise, `Some(n)` where `n` is the floating-point number
/// represented by `src`.
/// `Err(ParseIntError)` if the string did not represent a valid number. Otherwise,
/// Otherwise, `Ok(n)` where `n` is the floating-point number represented by `src`.
fn from_str_radix(src: &str, radix: u32)
-> Result<$T, ParseFloatError> {
use self::FloatErrorKind::*;

View file

@ -26,7 +26,7 @@ use syntax::codemap::{DUMMY_SP, Span};
use util::ppaux::Repr;
#[derive(Copy, Clone)]
struct ParamIsLocal(bool);
struct InferIsLocal(bool);
/// True if there exist types that satisfy both of the two given impls.
pub fn overlapping_impls(infcx: &InferCtxt,
@ -60,7 +60,7 @@ fn overlap(selcx: &mut SelectionContext,
let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx,
a_def_id,
util::free_substs_for_impl);
util::fresh_type_vars_for_impl);
let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx,
b_def_id,
@ -104,7 +104,7 @@ pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRe
// if the orphan rules pass, that means that no ancestor crate can
// impl this, so it's up to us.
if orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(false)).is_ok() {
if orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(false)).is_ok() {
debug!("trait_ref_is_knowable: orphan check passed");
return true;
}
@ -126,7 +126,7 @@ pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRe
// implemented by an upstream crate, which means that the impl
// must be visible to us, and -- since the trait is fundamental
// -- we can test.
orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(true)).is_err()
orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err()
}
type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>,
@ -196,16 +196,16 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
return Ok(());
}
orphan_check_trait_ref(tcx, &trait_ref, ParamIsLocal(false))
orphan_check_trait_ref(tcx, &trait_ref, InferIsLocal(false))
}
fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_ref: &ty::TraitRef<'tcx>,
param_is_local: ParamIsLocal)
infer_is_local: InferIsLocal)
-> Result<(), OrphanCheckErr<'tcx>>
{
debug!("orphan_check_trait_ref(trait_ref={}, param_is_local={})",
trait_ref.repr(tcx), param_is_local.0);
debug!("orphan_check_trait_ref(trait_ref={}, infer_is_local={})",
trait_ref.repr(tcx), infer_is_local.0);
// First, create an ordered iterator over all the type parameters to the trait, with the self
// type appearing first.
@ -215,12 +215,12 @@ fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
// Find the first input type that either references a type parameter OR
// some local type.
for input_ty in input_tys {
if ty_is_local(tcx, input_ty, param_is_local) {
if ty_is_local(tcx, input_ty, infer_is_local) {
debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx));
// First local input type. Check that there are no
// uncovered type parameters.
let uncovered_tys = uncovered_tys(tcx, input_ty, param_is_local);
let uncovered_tys = uncovered_tys(tcx, input_ty, infer_is_local);
for uncovered_ty in uncovered_tys {
if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) {
debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
@ -234,7 +234,7 @@ fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
// Otherwise, enforce invariant that there are no type
// parameters reachable.
if !param_is_local.0 {
if !infer_is_local.0 {
if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) {
debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
return Err(OrphanCheckErr::UncoveredTy(param));
@ -249,14 +249,14 @@ fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
fn uncovered_tys<'tcx>(tcx: &ty::ctxt<'tcx>,
ty: Ty<'tcx>,
param_is_local: ParamIsLocal)
infer_is_local: InferIsLocal)
-> Vec<Ty<'tcx>>
{
if ty_is_local_constructor(tcx, ty, param_is_local) {
if ty_is_local_constructor(tcx, ty, infer_is_local) {
vec![]
} else if fundamental_ty(tcx, ty) {
ty.walk_shallow()
.flat_map(|t| uncovered_tys(tcx, t, param_is_local).into_iter())
.flat_map(|t| uncovered_tys(tcx, t, infer_is_local).into_iter())
.collect()
} else {
vec![ty]
@ -271,10 +271,10 @@ fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
}
}
fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, param_is_local: ParamIsLocal) -> bool
fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, infer_is_local: InferIsLocal) -> bool
{
ty_is_local_constructor(tcx, ty, param_is_local) ||
fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, param_is_local))
ty_is_local_constructor(tcx, ty, infer_is_local) ||
fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, infer_is_local))
}
fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool
@ -293,7 +293,7 @@ fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool
fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
ty: Ty<'tcx>,
param_is_local: ParamIsLocal)
infer_is_local: InferIsLocal)
-> bool
{
debug!("ty_is_local_constructor({})", ty.repr(tcx));
@ -310,13 +310,13 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
ty::ty_ptr(..) |
ty::ty_rptr(..) |
ty::ty_tup(..) |
ty::ty_infer(..) |
ty::ty_param(..) |
ty::ty_projection(..) => {
false
}
ty::ty_param(..) => {
param_is_local.0
ty::ty_infer(..) => {
infer_is_local.0
}
ty::ty_enum(def_id, _) |

View file

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use middle::region;
use middle::subst::{Substs, VecPerParamSpace};
use middle::infer::InferCtxt;
use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef};
@ -304,34 +303,6 @@ pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
infcx.fresh_substs_for_generics(span, &impl_generics)
}
// determine the `self` type, using fresh variables for all variables
// declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>`
// would return ($0, $1) where $0 and $1 are freshly instantiated type
// variables.
pub fn free_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
_span: Span,
impl_def_id: ast::DefId)
-> Substs<'tcx>
{
let tcx = infcx.tcx;
let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics;
let some_types = impl_generics.types.map(|def| {
ty::mk_param_from_def(tcx, def)
});
let some_regions = impl_generics.regions.map(|def| {
// FIXME. This destruction scope information is pretty darn
// bogus; after all, the impl might not even be in this crate!
// But given what we do in coherence, it is harmless enough
// for now I think. -nmatsakis
let extent = region::DestructionScopeData::new(ast::DUMMY_NODE_ID);
ty::free_region_from_def(extent, def)
});
Substs::new(some_types, some_regions)
}
impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "VtableImpl({:?})", self.impl_def_id)

View file

@ -143,6 +143,13 @@ impl Session {
pub fn span_end_note(&self, sp: Span, msg: &str) {
self.diagnostic().span_end_note(sp, msg)
}
/// Prints out a message with a suggested edit of the code.
///
/// See `diagnostic::RenderSpan::Suggestion` for more information.
pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) {
self.diagnostic().span_suggestion(sp, msg, suggestion)
}
pub fn span_help(&self, sp: Span, msg: &str) {
self.diagnostic().span_help(sp, msg)
}

View file

@ -522,6 +522,16 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
pub fn report(&self, err: BckError<'tcx>) {
// Catch and handle some particular cases.
match (&err.code, &err.cause) {
(&err_out_of_scope(ty::ReScope(_), ty::ReStatic), &euv::ClosureCapture(span)) |
(&err_out_of_scope(ty::ReScope(_), ty::ReFree(..)), &euv::ClosureCapture(span)) => {
return self.report_out_of_scope_escaping_closure_capture(&err, span);
}
_ => { }
}
// General fallback.
self.span_err(
err.span,
&self.bckerr_to_string(&err));
@ -796,16 +806,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
format!("{} does not live long enough", msg)
}
err_borrowed_pointer_too_short(..) => {
let descr = match opt_loan_path(&err.cmt) {
Some(lp) => {
format!("`{}`", self.loan_path_to_string(&*lp))
}
None => self.cmt_to_string(&*err.cmt),
};
let descr = self.cmt_to_path_or_string(&err.cmt);
format!("lifetime of {} is too short to guarantee \
its contents can be safely reborrowed",
descr)
its contents can be safely reborrowed",
descr)
}
}
}
@ -888,6 +892,39 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
}
fn report_out_of_scope_escaping_closure_capture(&self,
err: &BckError<'tcx>,
capture_span: Span)
{
let cmt_path_or_string = self.cmt_to_path_or_string(&err.cmt);
span_err!(
self.tcx.sess, err.span, E0373,
"closure may outlive the current function, \
but it borrows {}, \
which is owned by the current function",
cmt_path_or_string);
self.tcx.sess.span_note(
capture_span,
&format!("{} is borrowed here",
cmt_path_or_string));
let suggestion =
match self.tcx.sess.codemap().span_to_snippet(err.span) {
Ok(string) => format!("move {}", string),
Err(_) => format!("move |<args>| <body>")
};
self.tcx.sess.span_suggestion(
err.span,
&format!("to force the closure to take ownership of {} \
(and any other referenced variables), \
use the `move` keyword, as shown:",
cmt_path_or_string),
suggestion);
}
pub fn note_and_explain_bckerr(&self, err: BckError<'tcx>) {
let code = err.code;
match code {
@ -1035,6 +1072,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
pub fn cmt_to_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
cmt.descriptive_string(self.tcx)
}
pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt<'tcx>) -> String {
match opt_loan_path(cmt) {
Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)),
None => self.cmt_to_string(cmt),
}
}
}
fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool {

View file

@ -0,0 +1,17 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(non_snake_case)]
register_diagnostics! {
E0373 // closure may outlive current fn, but it borrows {}, which is owned by current fn
}
__build_diagnostic_array! { DIAGNOSTICS }

View file

@ -40,6 +40,10 @@ pub use borrowck::check_crate;
pub use borrowck::build_borrowck_dataflow_data_for_fn;
pub use borrowck::FnPartsWithCFG;
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;
mod borrowck;
pub mod graphviz;

View file

@ -1107,7 +1107,7 @@ impl<K, V, S> HashMap<K, V, S>
self.search_mut(k).map(|bucket| bucket.into_mut_refs().1)
}
/// Inserts a key-value pair from the map. If the key already had a value
/// Inserts a key-value pair into the map. If the key already had a value
/// present in the map, that value is returned. Otherwise, `None` is returned.
///
/// # Examples

View file

@ -345,8 +345,8 @@ pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RecvError;
/// This enumeration is the list of the possible reasons that try_recv could not
/// return data when called.
/// This enumeration is the list of the possible reasons that `try_recv` could
/// not return data when called.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum TryRecvError {

View file

@ -367,7 +367,7 @@ impl Builder {
///
/// # Panics
///
/// Panicks if the OS fails to create a thread; use `Builder::spawn`
/// Panics if the OS fails to create a thread; use `Builder::spawn`
/// to recover from such errors.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn spawn<F>(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static {
@ -385,7 +385,7 @@ pub fn spawn<F>(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static {
///
/// # Panics
///
/// Panicks if the OS fails to create a thread; use `Builder::scoped`
/// Panics if the OS fails to create a thread; use `Builder::scoped`
/// to recover from such errors.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where

View file

@ -49,7 +49,7 @@ pub struct BytePos(pub u32);
/// A character offset. Because of multibyte utf8 characters, a byte offset
/// is not equivalent to a character offset. The CodeMap will convert BytePos
/// values to CharPos values as necessary.
#[derive(Copy, Clone, PartialEq, Hash, PartialOrd, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Debug)]
pub struct CharPos(pub usize);
// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
@ -305,9 +305,21 @@ impl ExpnId {
pub type FileName = String;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct LineInfo {
/// Index of line, starting from 0.
pub line_index: usize,
/// Column in line where span begins, starting from 0.
pub start_col: CharPos,
/// Column in line where span ends, starting from 0, exclusive.
pub end_col: CharPos,
}
pub struct FileLines {
pub file: Rc<FileMap>,
pub lines: Vec<usize>
pub lines: Vec<LineInfo>
}
/// Identifies an offset of a multi-byte character in a FileMap
@ -479,9 +491,9 @@ impl FileMap {
lines.push(pos);
}
/// get a line from the list of pre-computed line-beginnings
///
pub fn get_line(&self, line_number: usize) -> Option<String> {
/// get a line from the list of pre-computed line-beginnings.
/// line-number here is 0-based.
pub fn get_line(&self, line_number: usize) -> Option<&str> {
match self.src {
Some(ref src) => {
let lines = self.lines.borrow();
@ -492,7 +504,7 @@ impl FileMap {
match slice.find('\n') {
Some(e) => &slice[..e],
None => slice
}.to_string()
}
})
}
None => None
@ -661,10 +673,29 @@ impl CodeMap {
pub fn span_to_lines(&self, sp: Span) -> FileLines {
let lo = self.lookup_char_pos(sp.lo);
let hi = self.lookup_char_pos(sp.hi);
let mut lines = Vec::new();
for i in lo.line - 1..hi.line {
lines.push(i);
};
let mut lines = Vec::with_capacity(hi.line - lo.line + 1);
// The span starts partway through the first line,
// but after that it starts from offset 0.
let mut start_col = lo.col;
// For every line but the last, it extends from `start_col`
// and to the end of the line. Be careful because the line
// numbers in Loc are 1-based, so we subtract 1 to get 0-based
// lines.
for line_index in lo.line-1 .. hi.line-1 {
let line_len = lo.file.get_line(line_index).map(|s| s.len()).unwrap_or(0);
lines.push(LineInfo { line_index: line_index,
start_col: start_col,
end_col: CharPos::from_usize(line_len) });
start_col = CharPos::from_usize(0);
}
// For the last line, it extends from `start_col` to `hi.col`:
lines.push(LineInfo { line_index: hi.line - 1,
start_col: start_col,
end_col: hi.col });
FileLines {file: lo.file, lines: lines}
}
@ -919,6 +950,7 @@ pub struct MalformedCodemapPositions {
#[cfg(test)]
mod test {
use super::*;
use std::rc::Rc;
#[test]
fn t1 () {
@ -926,10 +958,10 @@ mod test {
let fm = cm.new_filemap("blork.rs".to_string(),
"first line.\nsecond line".to_string());
fm.next_line(BytePos(0));
assert_eq!(fm.get_line(0), Some("first line.".to_string()));
assert_eq!(fm.get_line(0), Some("first line."));
// TESTING BROKEN BEHAVIOR:
fm.next_line(BytePos(10));
assert_eq!(fm.get_line(1), Some(".".to_string()));
assert_eq!(fm.get_line(1), Some("."));
}
#[test]
@ -1057,7 +1089,54 @@ mod test {
assert_eq!(file_lines.file.name, "blork.rs");
assert_eq!(file_lines.lines.len(), 1);
assert_eq!(file_lines.lines[0], 1);
assert_eq!(file_lines.lines[0].line_index, 1);
}
/// Given a string like " ^~~~~~~~~~~~ ", produces a span
/// coverting that range. The idea is that the string has the same
/// length as the input, and we uncover the byte positions. Note
/// that this can span lines and so on.
fn span_from_selection(input: &str, selection: &str) -> Span {
assert_eq!(input.len(), selection.len());
let left_index = selection.find('^').unwrap() as u32;
let right_index = selection.rfind('~').unwrap() as u32;
Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION }
}
fn new_filemap_and_lines(cm: &CodeMap, filename: &str, input: &str) -> Rc<FileMap> {
let fm = cm.new_filemap(filename.to_string(), input.to_string());
let mut byte_pos: u32 = 0;
for line in input.lines() {
// register the start of this line
fm.next_line(BytePos(byte_pos));
// update byte_pos to include this line and the \n at the end
byte_pos += line.len() as u32 + 1;
}
fm
}
/// Test span_to_snippet and span_to_lines for a span coverting 3
/// lines in the middle of a file.
#[test]
fn span_to_snippet_and_lines_spanning_multiple_lines() {
let cm = CodeMap::new();
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
let selection = " \n ^~\n~~~\n~~~~~ \n \n";
new_filemap_and_lines(&cm, "blork.rs", inputtext);
let span = span_from_selection(inputtext, selection);
// check that we are extracting the text we thought we were extracting
assert_eq!(&cm.span_to_snippet(span).unwrap(), "BB\nCCC\nDDDDD");
// check that span_to_lines gives us the complete result with the lines/cols we expected
let lines = cm.span_to_lines(span);
let expected = vec![
LineInfo { line_index: 1, start_col: CharPos(4), end_col: CharPos(6) },
LineInfo { line_index: 2, start_col: CharPos(0), end_col: CharPos(3) },
LineInfo { line_index: 3, start_col: CharPos(0), end_col: CharPos(5) }
];
assert_eq!(lines.lines, expected);
}
#[test]

View file

@ -18,6 +18,7 @@ use codemap;
use diagnostics;
use std::cell::{RefCell, Cell};
use std::cmp;
use std::fmt;
use std::io::prelude::*;
use std::io;
@ -28,28 +29,39 @@ use libc;
/// maximum number of lines we will print for each error; arbitrary.
const MAX_LINES: usize = 6;
#[derive(Clone, Copy)]
#[derive(Clone)]
pub enum RenderSpan {
/// A FullSpan renders with both with an initial line for the
/// message, prefixed by file:linenum, followed by a summary of
/// the source code covered by the span.
FullSpan(Span),
/// Similar to a FullSpan, but the cited position is the end of
/// the span, instead of the start. Used, at least, for telling
/// compiletest/runtest to look at the last line of the span
/// (since `end_highlight_lines` displays an arrow to the end
/// of the span).
EndSpan(Span),
/// A suggestion renders with both with an initial line for the
/// message, prefixed by file:linenum, followed by a summary
/// of hypothetical source code, where the `String` is spliced
/// into the lines in place of the code covered by the span.
Suggestion(Span, String),
/// A FileLine renders with just a line for the message prefixed
/// by file:linenum.
FileLine(Span),
}
impl RenderSpan {
fn span(self) -> Span {
match self {
FullSpan(s) | FileLine(s) => s
}
}
fn is_full_span(&self) -> bool {
match self {
&FullSpan(..) => true,
&FileLine(..) => false,
fn span(&self) -> Span {
match *self {
FullSpan(s) |
Suggestion(s, _) |
EndSpan(s) |
FileLine(s) =>
s
}
}
}
@ -115,11 +127,17 @@ impl SpanHandler {
self.handler.emit(Some((&self.cm, sp)), msg, Note);
}
pub fn span_end_note(&self, sp: Span, msg: &str) {
self.handler.custom_emit(&self.cm, FullSpan(sp), msg, Note);
self.handler.custom_emit(&self.cm, EndSpan(sp), msg, Note);
}
pub fn span_help(&self, sp: Span, msg: &str) {
self.handler.emit(Some((&self.cm, sp)), msg, Help);
}
/// Prints out a message with a suggested edit of the code.
///
/// See `diagnostic::RenderSpan::Suggestion` for more information.
pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) {
self.handler.custom_emit(&self.cm, Suggestion(sp, suggestion), msg, Help);
}
pub fn fileline_note(&self, sp: Span, msg: &str) {
self.handler.custom_emit(&self.cm, FileLine(sp), msg, Note);
}
@ -407,8 +425,8 @@ impl Emitter for EmitterWriter {
let error = match cmsp {
Some((cm, COMMAND_LINE_SP)) => emit(self, cm,
FileLine(COMMAND_LINE_SP),
msg, code, lvl, false),
Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl, false),
msg, code, lvl),
Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl),
None => print_diagnostic(self, "", lvl, msg, code),
};
@ -420,7 +438,7 @@ impl Emitter for EmitterWriter {
fn custom_emit(&mut self, cm: &codemap::CodeMap,
sp: RenderSpan, msg: &str, lvl: Level) {
match emit(self, cm, sp, msg, None, lvl, true) {
match emit(self, cm, sp, msg, None, lvl) {
Ok(()) => {}
Err(e) => panic!("failed to print diagnostics: {:?}", e),
}
@ -428,35 +446,41 @@ impl Emitter for EmitterWriter {
}
fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
msg: &str, code: Option<&str>, lvl: Level, custom: bool) -> io::Result<()> {
msg: &str, code: Option<&str>, lvl: Level) -> io::Result<()> {
let sp = rsp.span();
// We cannot check equality directly with COMMAND_LINE_SP
// since PartialEq is manually implemented to ignore the ExpnId
let ss = if sp.expn_id == COMMAND_LINE_EXPN {
"<command line option>".to_string()
} else if let EndSpan(_) = rsp {
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id};
cm.span_to_string(span_end)
} else {
cm.span_to_string(sp)
};
if custom {
// we want to tell compiletest/runtest to look at the last line of the
// span (since `custom_highlight_lines` displays an arrow to the end of
// the span)
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id};
let ses = cm.span_to_string(span_end);
try!(print_diagnostic(dst, &ses[..], lvl, msg, code));
if rsp.is_full_span() {
try!(custom_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp)));
}
} else {
try!(print_diagnostic(dst, &ss[..], lvl, msg, code));
if rsp.is_full_span() {
try!(print_diagnostic(dst, &ss[..], lvl, msg, code));
match rsp {
FullSpan(_) => {
try!(highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp)));
}
EndSpan(_) => {
try!(end_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp)));
}
Suggestion(_, ref suggestion) => {
try!(highlight_suggestion(dst, cm, sp, suggestion));
}
FileLine(..) => {
// no source text in this case!
}
}
if sp != COMMAND_LINE_SP {
try!(print_macro_backtrace(dst, cm, sp));
}
match code {
Some(code) =>
match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) {
@ -472,29 +496,90 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
Ok(())
}
fn highlight_suggestion(err: &mut EmitterWriter,
cm: &codemap::CodeMap,
sp: Span,
suggestion: &str)
-> io::Result<()>
{
let lines = cm.span_to_lines(sp);
assert!(!lines.lines.is_empty());
// To build up the result, we want to take the snippet from the first
// line that precedes the span, prepend that with the suggestion, and
// then append the snippet from the last line that trails the span.
let fm = &lines.file;
let first_line = &lines.lines[0];
let prefix = fm.get_line(first_line.line_index)
.map(|l| &l[..first_line.start_col.0])
.unwrap_or("");
let last_line = lines.lines.last().unwrap();
let suffix = fm.get_line(last_line.line_index)
.map(|l| &l[last_line.end_col.0..])
.unwrap_or("");
let complete = format!("{}{}{}", prefix, suggestion, suffix);
// print the suggestion without any line numbers, but leave
// space for them. This helps with lining up with previous
// snippets from the actual error being reported.
let fm = &*lines.file;
let mut lines = complete.lines();
for (line, line_index) in lines.by_ref().take(MAX_LINES).zip(first_line.line_index..) {
let elided_line_num = format!("{}", line_index+1);
try!(write!(&mut err.dst, "{0}:{1:2$} {3}\n",
fm.name, "", elided_line_num.len(), line));
}
// if we elided some lines, add an ellipsis
if lines.next().is_some() {
let elided_line_num = format!("{}", first_line.line_index + MAX_LINES + 1);
try!(write!(&mut err.dst, "{0:1$} {0:2$} ...\n",
"", fm.name.len(), elided_line_num.len()));
}
Ok(())
}
fn highlight_lines(err: &mut EmitterWriter,
cm: &codemap::CodeMap,
sp: Span,
lvl: Level,
lines: codemap::FileLines) -> io::Result<()> {
lines: codemap::FileLines)
-> io::Result<()>
{
let fm = &*lines.file;
let mut elided = false;
let mut display_lines = &lines.lines[..];
if display_lines.len() > MAX_LINES {
display_lines = &display_lines[0..MAX_LINES];
elided = true;
}
let line_strings: Option<Vec<&str>> =
lines.lines.iter()
.map(|info| fm.get_line(info.line_index))
.collect();
let line_strings = match line_strings {
None => { return Ok(()); }
Some(line_strings) => line_strings
};
// Display only the first MAX_LINES lines.
let all_lines = lines.lines.len();
let display_lines = cmp::min(all_lines, MAX_LINES);
let display_line_infos = &lines.lines[..display_lines];
let display_line_strings = &line_strings[..display_lines];
// Print the offending lines
for &line_number in display_lines {
if let Some(line) = fm.get_line(line_number) {
try!(write!(&mut err.dst, "{}:{} {}\n", fm.name,
line_number + 1, line));
}
for (line_info, line) in display_line_infos.iter().zip(display_line_strings.iter()) {
try!(write!(&mut err.dst, "{}:{} {}\n",
fm.name,
line_info.line_index + 1,
line));
}
if elided {
let last_line = display_lines[display_lines.len() - 1];
let s = format!("{}:{} ", fm.name, last_line + 1);
// If we elided something, put an ellipsis.
if display_lines < all_lines {
let last_line_index = display_line_infos.last().unwrap().line_index;
let s = format!("{}:{} ", fm.name, last_line_index + 1);
try!(write!(&mut err.dst, "{0:1$}...\n", "", s.len()));
}
@ -503,7 +588,7 @@ fn highlight_lines(err: &mut EmitterWriter,
if lines.lines.len() == 1 {
let lo = cm.lookup_char_pos(sp.lo);
let mut digits = 0;
let mut num = (lines.lines[0] + 1) / 10;
let mut num = (lines.lines[0].line_index + 1) / 10;
// how many digits must be indent past?
while num > 0 { num /= 10; digits += 1; }
@ -515,7 +600,7 @@ fn highlight_lines(err: &mut EmitterWriter,
for _ in 0..skip {
s.push(' ');
}
if let Some(orig) = fm.get_line(lines.lines[0]) {
if let Some(orig) = fm.get_line(lines.lines[0].line_index) {
let mut col = skip;
let mut lastc = ' ';
let mut iter = orig.chars().enumerate();
@ -575,12 +660,12 @@ fn highlight_lines(err: &mut EmitterWriter,
}
/// Here are the differences between this and the normal `highlight_lines`:
/// `custom_highlight_lines` will always put arrow on the last byte of the
/// `end_highlight_lines` will always put arrow on the last byte of the
/// span (instead of the first byte). Also, when the span is too long (more
/// than 6 lines), `custom_highlight_lines` will print the first line, then
/// than 6 lines), `end_highlight_lines` will print the first line, then
/// dot dot dot, then last line, whereas `highlight_lines` prints the first
/// six lines.
fn custom_highlight_lines(w: &mut EmitterWriter,
fn end_highlight_lines(w: &mut EmitterWriter,
cm: &codemap::CodeMap,
sp: Span,
lvl: Level,
@ -590,32 +675,32 @@ fn custom_highlight_lines(w: &mut EmitterWriter,
let lines = &lines.lines[..];
if lines.len() > MAX_LINES {
if let Some(line) = fm.get_line(lines[0]) {
if let Some(line) = fm.get_line(lines[0].line_index) {
try!(write!(&mut w.dst, "{}:{} {}\n", fm.name,
lines[0] + 1, line));
lines[0].line_index + 1, line));
}
try!(write!(&mut w.dst, "...\n"));
let last_line_number = lines[lines.len() - 1];
if let Some(last_line) = fm.get_line(last_line_number) {
let last_line_index = lines[lines.len() - 1].line_index;
if let Some(last_line) = fm.get_line(last_line_index) {
try!(write!(&mut w.dst, "{}:{} {}\n", fm.name,
last_line_number + 1, last_line));
last_line_index + 1, last_line));
}
} else {
for &line_number in lines {
if let Some(line) = fm.get_line(line_number) {
for line_info in lines {
if let Some(line) = fm.get_line(line_info.line_index) {
try!(write!(&mut w.dst, "{}:{} {}\n", fm.name,
line_number + 1, line));
line_info.line_index + 1, line));
}
}
}
let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1]+1);
let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1].line_index + 1);
let hi = cm.lookup_char_pos(sp.hi);
let skip = last_line_start.width(false);
let mut s = String::new();
for _ in 0..skip {
s.push(' ');
}
if let Some(orig) = fm.get_line(lines[0]) {
if let Some(orig) = fm.get_line(lines[0].line_index) {
let iter = orig.chars().enumerate();
for (pos, ch) in iter {
// Span seems to use half-opened interval, so subtract 1

View file

@ -0,0 +1,25 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::thread::spawn;
// Test that we give a custom error (E0373) for the case where a
// closure is escaping current frame, and offer a suggested code edit.
// I refrained from including the precise message here, but the
// original text as of the time of this writing is:
//
// closure may outlive the current function, but it borrows `books`,
// which is owned by the current function
fn main() {
let mut books = vec![1,2,3];
spawn(|| books.push(4));
//~^ ERROR E0373
}

View file

@ -0,0 +1,25 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that we give a custom error (E0373) for the case where a
// closure is escaping current frame, and offer a suggested code edit.
// I refrained from including the precise message here, but the
// original text as of the time of this writing is:
//
// closure may outlive the current function, but it borrows `books`,
// which is owned by the current function
fn foo<'a>(x: &'a i32) -> Box<FnMut()+'a> {
let mut books = vec![1,2,3];
Box::new(|| books.push(4))
//~^ ERROR E0373
}
fn main() { }

View file

@ -0,0 +1,28 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that we detect an overlap here in the case where:
//
// for some type X:
// T = (X,)
// T11 = X, U11 = X
//
// Seems pretty basic, but then there was issue #24241. :)
trait From<U> {
}
impl <T> From<T> for T { //~ ERROR E0119
}
impl <T11, U11> From<(U11,)> for (T11,) {
}
fn main() { }

View file

@ -18,10 +18,10 @@ trait Collection { fn len(&self) -> usize; }
struct List<'a, T: ListItem<'a>> {
//~^ ERROR the parameter type `T` may not live long enough
//~^^ NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at
//~| HELP consider adding an explicit lifetime bound
//~| NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at
slice: &'a [T]
}
//~^ HELP consider adding an explicit lifetime bound
impl<'a, T: ListItem<'a>> Collection for List<'a, T> {
fn len(&self) -> usize {
0

View file

@ -0,0 +1,15 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait T : Iterator<Item=Self::Item>
//~^ ERROR unsupported cyclic reference between types/traits detected
{}
fn main() {}

View file

@ -0,0 +1,16 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait Foo {}
impl<'a> Foo for Foo+'a {}
//~^ ERROR the object type `Foo + 'a` automatically implements the trait `Foo`
fn main() {}

View file

@ -0,0 +1,20 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-tidy-linelength
use std::ops::Add;
fn main() {
let x = &10 as
//~^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified
&Add;
//~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self`
}

View file

@ -0,0 +1,19 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate libc;
fn main() {
let foo: *mut libc::c_void;
let cb: &mut Fn() = unsafe {
&mut *(foo as *mut Fn())
//~^ ERROR use of possibly uninitialized variable: `foo`
};
}

View file

@ -15,7 +15,7 @@ fn id<T>(t: T) -> T { t }
fn f<'r, T>(v: &'r T) -> Box<FnMut() -> T + 'r> {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
id(Box::new(|| *v))
//~^ ERROR `v` does not live long enough
//~^ ERROR E0373
//~| ERROR cannot move out of borrowed content
}

View file

@ -13,7 +13,7 @@ fn ignore<F>(_f: F) where F: for<'z> FnOnce(&'z isize) -> &'z isize {}
fn nested() {
let y = 3;
ignore(
|z| { //~ ERROR `y` does not live long enough
|z| { //~ ERROR E0373
if false { &y } else { z }
});
}

View file

@ -0,0 +1,22 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// regression test for #19097
struct Foo<T>(T);
impl<'a, T> Foo<&'a T> {
fn foo(&self) {}
}
impl<'a, T> Foo<&'a mut T> {
fn foo(&self) {}
}
fn main() {}