Auto merge of #24328 - Manishearth:rollup, r=Manishearth
This commit is contained in:
commit
6790b0e519
55 changed files with 1587 additions and 1524 deletions
|
|
@ -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 aren’t
|
||||
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 aren’t 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, you’ll 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? Let’s 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 they’re 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.
|
||||
We’ll be mutating this vector later in the example.
|
||||
|
||||
This chapter contains things that are only available on the nightly channel of
|
||||
Rust.
|
||||
It’s also worth noting that we didn’t need a type annotation here: while Rust
|
||||
is statically typed, we didn’t 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 you’re 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 we’re getting started, it’s 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 vector’s 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 don’t 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.
|
||||
|
||||
Let’s add another line to our example:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mut x = vec!["Hello", "world"];
|
||||
|
||||
let y = &x[0];
|
||||
}
|
||||
```
|
||||
|
||||
We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to
|
||||
the first element of the vector. Rust’s 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, we’d
|
||||
de-allocate twice, which is bad!
|
||||
|
||||
[borrowing]: references-and-borrowing.html
|
||||
|
||||
Let’s 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` wouldn’t get updated, and so
|
||||
we’d have a ‘dangling pointer’. That’s 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 don’t 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 we’re all good.
|
||||
|
||||
This concept of ownership isn’t just good for preventing danging pointers, but an
|
||||
entire set of related problems, like iterator invalidation, concurrency, and more.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
46
src/doc/trpl/academic-research.md
Normal file
46
src/doc/trpl/academic-research.md
Normal 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
|
||||
|
|
@ -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.
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
% `Debug` and `Display`
|
||||
% Debug and Display
|
||||
|
||||
Coming soon!
|
||||
|
|
|
|||
|
|
@ -1 +1,8 @@
|
|||
% Effective Rust
|
||||
|
||||
So you’ve learned how to write some Rust code. But there’s 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.
|
||||
|
|
|
|||
|
|
@ -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. Rust’s `for` loops
|
||||
work a bit differently than in other systems languages, however. Rust’s `for`
|
||||
loop doesn’t look like this “C-style” `for` loop:
|
||||
|
||||
```{c}
|
||||
```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.
|
||||
|
|
|
|||
|
|
@ -1 +1,5 @@
|
|||
% Getting Started
|
||||
|
||||
This first section of the book will get you going with Rust and its tooling.
|
||||
First, we’ll install Rust. Then: the classic ‘Hello World’ program. Finally,
|
||||
we’ll talk about Cargo, Rust’s build system and package manager.
|
||||
|
|
|
|||
|
|
@ -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 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
|
||||
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.
|
||||
Let’s 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. Let’s 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 didn’t re-build the project this time. Cargo figured out that
|
||||
we hadn’t 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 hasn’t 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 it’ll 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 don’t have any, so it’s 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.
|
||||
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. 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 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.
|
||||
|
||||
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.
|
||||
We’re 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
|
||||
distribution’s package manager. It’s not necessary, but it’s 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, let’s 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`:
|
||||
Here’s what’s 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 you’re ready to start coding! Cargo
|
||||
has its own [guide][guide] which covers Cargo’s 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 you’ve got the tools down, let’s 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 whatever’s right for you.
|
||||
|
||||
[learnrust]: learn-rust.html
|
||||
[syntax]: syntax-and-semantics.html
|
||||
|
|
|
|||
|
|
@ -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, let’s write your first Rust program. It’s
|
||||
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 isn’t 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, let’s 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 you’re 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`:
|
||||
Let’s make a new source file next. We’ll call our file `main.rs`. 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`.
|
||||
|
||||
```{bash}
|
||||
$ editor main.rs
|
||||
```
|
||||
Now that you’ve 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! Let’s 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 "I’m 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 aren’t returning anything from this function, we can omit the return type
|
||||
entirely. We’ll get to it later.
|
||||
|
||||
You'll also note that the function is wrapped in curly braces (`{` and `}`).
|
||||
You’ll 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 it’s 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 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 an
|
||||
advanced topic. 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.
|
||||
|
||||
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 don’t need to right now if you don’t 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
3
src/doc/trpl/if-let.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
% if let
|
||||
|
||||
COMING SOON
|
||||
|
|
@ -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.
|
||||
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.
|
||||
|
||||
`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 it’s `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.
|
||||
|
|
|
|||
|
|
@ -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 user’s 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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
% Match
|
||||
|
||||
Often, a simple `if`/`else` isn't enough, because you have more than two
|
||||
Often, a simple `if`/`else` isn’t enough, because you have more than two
|
||||
possible options. Also, `else` conditions can get incredibly complicated, so
|
||||
what's the solution?
|
||||
what’s 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 arm’s
|
||||
expression will be evaluated. It’s called `match` because of the term ‘pattern
|
||||
matching’, which `match` is an implementation of. There’s an [entire section on
|
||||
patterns][patterns] coming up next, that covers all the options that fit here.
|
||||
|
||||
So what's the big advantage here? Well, there are a few. First of all, `match`
|
||||
[patterns]: patterns.html
|
||||
|
||||
So what’s the big advantage here? Well, there are a few. First of all, `match`
|
||||
enforces *exhaustiveness checking*. Do you see that last arm, the one with the
|
||||
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, it’s a nice way of converting things.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 user’s 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
|
||||
|
|
|
|||
|
|
@ -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. Let’s 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 you’re 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 you’re 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 don’t 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! That’s a lot of different ways to match things, and they can all be
|
||||
mixed and matched, depending on what you’re doing:
|
||||
|
||||
```{rust,ignore}
|
||||
match x {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,268 @@
|
|||
% Primitive Types
|
||||
|
||||
Coming Soon!
|
||||
The Rust language has a number of types that are considered ‘primitive’. This
|
||||
means that they’re 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 Rust’s `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
|
||||
```
|
||||
|
||||
Here’s 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)
|
||||
|
||||
Let’s go over them by category:
|
||||
|
||||
## Signed and Unsigned
|
||||
|
||||
Integer types come in two varieties: signed and unsigned. To understand the
|
||||
difference, let’s 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
|
||||
‘two’s 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]`. We’ll talk about this `T` notation [in the generics
|
||||
section][generics]. The `N` is a compile-time constant, for the length of the
|
||||
array.
|
||||
|
||||
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]
|
||||
```
|
||||
|
||||
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]`. We’ll 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`
|
||||
|
||||
Rust’s `str` type is the most primitive string type. As an [unsized type][dst],
|
||||
it’s not very useful by itself, but becomes useful when placed behind a reference,
|
||||
like [`&str`][strings]. As such, we’ll 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. 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.
|
||||
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][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 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.
|
||||
|
||||
[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`.
|
||||
|
|
|
|||
18
src/doc/trpl/slice-patterns.md
Normal file
18
src/doc/trpl/slice-patterns.md
Normal 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),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -1 +1,10 @@
|
|||
% Syntax and Semantics
|
||||
|
||||
This section breaks Rust down into small chunks, one for each concept.
|
||||
|
||||
If you’d 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 you’re reading
|
||||
another tutorial and find something confusing, you can find it explained
|
||||
somewhere in here.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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 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.
|
||||
|
||||
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 Rust’s 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 don’t need those features for now, so we’ll 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 they’re 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 doesn’t 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, you’d 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 Rust’s 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 they’re
|
||||
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 it’s not verboten.
|
||||
|
||||
Let's get back to bindings. Rust variable bindings have one more aspect that
|
||||
Let’s 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:
|
||||
Let’s 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. You’ll 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. Let’s 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. You’ll 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, let’s
|
||||
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 we’re interpolating. The comma is used to separate
|
||||
arguments we pass to functions and macros, if you’re 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
|
||||
|
|
|
|||
|
|
@ -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 you’re 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.
|
||||
Rust’s 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:
|
||||
Let’s 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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, _) |
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
17
src/librustc_borrowck/diagnostics.rs
Normal file
17
src/librustc_borrowck/diagnostics.rs
Normal 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 }
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
25
src/test/compile-fail/borrowck-escaping-closure-error-1.rs
Normal file
25
src/test/compile-fail/borrowck-escaping-closure-error-1.rs
Normal 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
|
||||
}
|
||||
25
src/test/compile-fail/borrowck-escaping-closure-error-2.rs
Normal file
25
src/test/compile-fail/borrowck-escaping-closure-error-2.rs
Normal 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() { }
|
||||
28
src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs
Normal file
28
src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs
Normal 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() { }
|
||||
|
|
@ -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
|
||||
|
|
|
|||
15
src/test/compile-fail/issue-20772.rs
Normal file
15
src/test/compile-fail/issue-20772.rs
Normal 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() {}
|
||||
16
src/test/compile-fail/issue-20939.rs
Normal file
16
src/test/compile-fail/issue-20939.rs
Normal 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() {}
|
||||
20
src/test/compile-fail/issue-21950.rs
Normal file
20
src/test/compile-fail/issue-21950.rs
Normal 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`
|
||||
}
|
||||
19
src/test/compile-fail/issue-22034.rs
Normal file
19
src/test/compile-fail/issue-22034.rs
Normal 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`
|
||||
};
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
});
|
||||
}
|
||||
|
|
|
|||
22
src/test/run-pass/issue-19097.rs
Normal file
22
src/test/run-pass/issue-19097.rs
Normal 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() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue