Fix dead links in the guide and reorganize
This commit is contained in:
parent
483fca9fa5
commit
7541f82fab
@ -275,9 +275,8 @@ endif
|
||||
docs: $(DOC_TARGETS)
|
||||
compiler-docs: $(COMPILER_DOC_TARGETS)
|
||||
|
||||
trpl: tmp/trpl.ok
|
||||
trpl: doc/book/index.html
|
||||
|
||||
tmp/trpl.ok: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/trpl/*.md)
|
||||
doc/book/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/trpl/*.md)
|
||||
$(Q)rm -rf doc/book
|
||||
$(Q)$(RUSTBOOK) build $(S)src/doc/trpl doc/book
|
||||
$(Q)touch $@
|
||||
|
@ -156,8 +156,8 @@ endef
|
||||
|
||||
$(foreach doc,$(DOCS), \
|
||||
$(eval $(call DOCTEST,md-$(doc),$(S)src/doc/$(doc).md)))
|
||||
$(foreach file,$(wildcard $(S)src/doc/trpl/src/*), \
|
||||
$(eval $(call DOCTEST,$(file:$(S)src/doc/trpl/src/%.md=trpl-%),$(file))))
|
||||
$(foreach file,$(wildcard $(S)src/doc/trpl/*.md), \
|
||||
$(eval $(call DOCTEST,$(file:$(S)src/doc/trpl/%.md=trpl-%),$(file))))
|
||||
|
||||
######################################################################
|
||||
# Main test targets
|
||||
|
@ -1,35 +1,36 @@
|
||||
# Summary
|
||||
|
||||
* [I: The Basics](src/basic.md)
|
||||
* [Installing Rust](src/installing-rust.md)
|
||||
* [Hello, world!](src/hello-world.md)
|
||||
* [Hello, Cargo!](src/hello-cargo.md)
|
||||
* [Variable Bindings](src/variable-bindings.md)
|
||||
* [If](src/if.md)
|
||||
* [Functions](src/functions.md)
|
||||
* [Comments](src/comments.md)
|
||||
* [Compound Data Types](src/compound-data-types.md)
|
||||
* [Match](src/match.md)
|
||||
* [Looping](src/looping.md)
|
||||
* [Strings](src/strings.md)
|
||||
* [Arrays, Vectors, and Slices](src/arrays-vectors-and-slices.md)
|
||||
* [Standard Input](src/standard-input.md)
|
||||
* [Guessing Game](src/guessing-game.md)
|
||||
* [II: Intermedite Rust](src/intermediate.md)
|
||||
* [Crates and Modules](src/crates-and-modules.md)
|
||||
* [Testing](src/testing.md)
|
||||
* [Pointers](src/pointers.md)
|
||||
* [Patterns](src/patterns.md)
|
||||
* [Method Syntax](src/method-syntax.md)
|
||||
* [Closures](src/closures.md)
|
||||
* [Iterators](src/iterators.md)
|
||||
* [Generics](src/generics.md)
|
||||
* [Traits](src/traits.md)
|
||||
* [Tasks](src/tasks.md)
|
||||
* [Error Handling](src/error-handling.md)
|
||||
* [III: Advanced Topics](src/advanced.md)
|
||||
* [FFI](src/ffi.md)
|
||||
* [Unsafe Code](src/unsafe.md)
|
||||
* [Macros](src/macros.md)
|
||||
* [Compiler Plugins](src/plugins.md)
|
||||
* [Conclusion](src/conclusion.md)
|
||||
* [I: The Basics](basic.md)
|
||||
* [Installing Rust](installing-rust.md)
|
||||
* [Hello, world!](hello-world.md)
|
||||
* [Hello, Cargo!](hello-cargo.md)
|
||||
* [Variable Bindings](variable-bindings.md)
|
||||
* [If](if.md)
|
||||
* [Functions](functions.md)
|
||||
* [Comments](comments.md)
|
||||
* [Compound Data Types](compound-data-types.md)
|
||||
* [Match](match.md)
|
||||
* [Looping](looping.md)
|
||||
* [Strings](strings.md)
|
||||
* [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md)
|
||||
* [Standard Input](standard-input.md)
|
||||
* [Guessing Game](guessing-game.md)
|
||||
* [II: Intermediate Rust](intermediate.md)
|
||||
* [Crates and Modules](crates-and-modules.md)
|
||||
* [Testing](testing.md)
|
||||
* [Pointers](pointers.md)
|
||||
* [Ownership](ownership.md)
|
||||
* [Patterns](patterns.md)
|
||||
* [Method Syntax](method-syntax.md)
|
||||
* [Closures](closures.md)
|
||||
* [Iterators](iterators.md)
|
||||
* [Generics](generics.md)
|
||||
* [Traits](traits.md)
|
||||
* [Tasks](tasks.md)
|
||||
* [Error Handling](error-handling.md)
|
||||
* [III: Advanced Topics](advanced.md)
|
||||
* [FFI](ffi.md)
|
||||
* [Unsafe Code](unsafe.md)
|
||||
* [Macros](macros.md)
|
||||
* [Compiler Plugins](plugins.md)
|
||||
* [Conclusion](conclusion.md)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Arrays, Vectors, and Slices
|
||||
% Arrays, Vectors, and Slices
|
||||
|
||||
Like many programming languages, Rust has list types to represent a sequence of
|
||||
things. The most basic is the **array**, a fixed-size list of elements of the
|
||||
@ -48,7 +48,7 @@ errant access is the source of many bugs in other systems programming
|
||||
languages.
|
||||
|
||||
A **vector** is a dynamic or "growable" array, implemented as the standard
|
||||
library type [`Vec<T>`](std/vec/) (we'll talk about what the `<T>` means
|
||||
library type [`Vec<T>`](../std/vec/) (we'll talk about what the `<T>` means
|
||||
later). Vectors are to arrays what `String` is to `&str`. You can create them
|
||||
with the `vec!` macro:
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Closures
|
||||
% Closures
|
||||
|
||||
So far, we've made lots of functions in Rust, but we've given them all names.
|
||||
Rust also allows us to create anonymous functions. Rust's anonymous
|
@ -1,4 +1,4 @@
|
||||
# Comments
|
||||
% Comments
|
||||
|
||||
Now that we have some functions, it's a good idea to learn about comments.
|
||||
Comments are notes that you leave to other programmers to help explain things
|
||||
@ -42,5 +42,5 @@ fn hello(name: &str) {
|
||||
When writing doc comments, adding sections for any arguments, return values,
|
||||
and providing some examples of usage is very, very helpful.
|
||||
|
||||
You can use the [`rustdoc`](rustdoc.html) tool to generate HTML documentation
|
||||
You can use the [`rustdoc`](../rustdoc.html) tool to generate HTML documentation
|
||||
from these doc comments.
|
@ -1,4 +1,4 @@
|
||||
# Compound Data Types
|
||||
% Compound Data Types
|
||||
|
||||
Rust, like many programming languages, has a number of different data types
|
||||
that are built-in. You've already done some simple work with integers and
|
@ -1,4 +1,4 @@
|
||||
# Functions
|
||||
% Functions
|
||||
|
||||
You've already seen one function so far, the `main` function:
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Guessing Game
|
||||
% Guessing Game
|
||||
|
||||
Okay! We've got the basics of Rust down. Let's write a bigger program.
|
||||
|
||||
@ -108,12 +108,12 @@ we do know that Rust has random number generation, but we don't know how to
|
||||
use it.
|
||||
|
||||
Enter the docs. Rust has a page specifically to document the standard library.
|
||||
You can find that page [here](std/index.html). There's a lot of information on
|
||||
You can find that page [here](../std/index.html). There's a lot of information on
|
||||
that page, but the best part is the search bar. Right up at the top, there's
|
||||
a box that you can enter in a search term. The search is pretty primitive
|
||||
right now, but is getting better all the time. If you type 'random' in that
|
||||
box, the page will update to [this one](std/index.html?search=random). The very
|
||||
first result is a link to [`std::rand::random`](std/rand/fn.random.html). If we
|
||||
box, the page will update to [this one](../std/index.html?search=random). The very
|
||||
first result is a link to [`std::rand::random`](../std/rand/fn.random.html). If we
|
||||
click on that result, we'll be taken to its documentation page.
|
||||
|
||||
This page shows us a few things: the type signature of the function, some
|
@ -1,4 +1,4 @@
|
||||
# Hello, Cargo!
|
||||
% Hello, Cargo!
|
||||
|
||||
[Cargo](http://crates.io) is a tool that Rustaceans use to help manage their
|
||||
Rust projects. Cargo is currently in an alpha state, just like Rust, and so it
|
@ -1,4 +1,4 @@
|
||||
# Hello, world!
|
||||
% Hello, world!
|
||||
|
||||
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
|
@ -1,4 +1,4 @@
|
||||
# `if`
|
||||
% `if`
|
||||
|
||||
Rust's take on `if` is not particularly complex, but it's much more like the
|
||||
`if` you'll find in a dynamically typed language than in a more traditional
|
@ -1,4 +1,4 @@
|
||||
# Installing Rust
|
||||
% 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
|
@ -336,4 +336,4 @@ can help you with. There are a number of really useful iterators, and you can
|
||||
write your own as well. Iterators provide a safe, efficient way to manipulate
|
||||
all kinds of lists. They're a little unusual at first, but if you play with
|
||||
them, you'll get hooked. For a full list of the different iterators and
|
||||
consumers, check out the [iterator module documentation](std/iter/index.html).
|
||||
consumers, check out the [iterator module documentation](../std/iter/index.html).
|
@ -1,4 +1,4 @@
|
||||
# Looping
|
||||
% Looping
|
||||
|
||||
Looping is the last basic construct that we haven't learned yet in Rust. Rust has
|
||||
two main looping constructs: `for` and `while`.
|
@ -507,7 +507,7 @@ When this library is loaded with `#[use_macros] extern crate`, only `m2` will
|
||||
be imported.
|
||||
|
||||
The Rust Reference has a [listing of macro-related
|
||||
attributes](reference.html#macro--and-plugin-related-attributes).
|
||||
attributes](../reference.html#macro--and-plugin-related-attributes).
|
||||
|
||||
# The variable `$crate`
|
||||
|
||||
@ -567,7 +567,7 @@ intermediate states out, and passing the flag `--pretty expanded` as a
|
||||
command-line argument to the compiler will show the result of expansion.
|
||||
|
||||
If Rust's macro system can't do what you need, you may want to write a
|
||||
[compiler plugin](guide-plugin.html) instead. Compared to `macro_rules!`
|
||||
[compiler plugin](plugin.html) instead. Compared to `macro_rules!`
|
||||
macros, this is significantly more work, the interfaces are much less stable,
|
||||
and the warnings about debugging apply ten-fold. In exchange you get the
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
@ -1,4 +1,4 @@
|
||||
# Match
|
||||
% Match
|
||||
|
||||
Often, a simple `if`/`else` isn't enough, because you have more than two
|
||||
possible options. Also, `else` conditions can get incredibly complicated, so
|
@ -5,20 +5,20 @@
|
||||
<p>
|
||||
<b>Warning:</b> Plugins are an advanced, unstable feature! For many details,
|
||||
the only available documentation is the <a
|
||||
href="syntax/index.html"><code>libsyntax</code></a> and <a
|
||||
href="rustc/index.html"><code>librustc</code></a> API docs, or even the source
|
||||
href="../syntax/index.html"><code>libsyntax</code></a> and <a
|
||||
href="../rustc/index.html"><code>librustc</code></a> API docs, or even the source
|
||||
code itself. These internal compiler APIs are also subject to change at any
|
||||
time.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For defining new syntax it is often much easier to use Rust's <a
|
||||
href="guide-macros.html">built-in macro system</a>.
|
||||
href="macros.html">built-in macro system</a>.
|
||||
</p>
|
||||
|
||||
<p style="margin-bottom: 0">
|
||||
The code in this document uses language features not covered in the Rust
|
||||
Guide. See the <a href="reference.html">Reference Manual</a> for more
|
||||
Guide. See the <a href="../reference.html">Reference Manual</a> for more
|
||||
information.
|
||||
</p>
|
||||
|
||||
@ -32,19 +32,19 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc.
|
||||
A plugin is a dynamic library crate with a designated "registrar" function that
|
||||
registers extensions with `rustc`. Other crates can use these extensions by
|
||||
loading the plugin crate with `#[plugin] extern crate`. See the
|
||||
[`rustc::plugin`](rustc/plugin/index.html) documentation for more about the
|
||||
[`rustc::plugin`](../rustc/plugin/index.html) documentation for more about the
|
||||
mechanics of defining and loading a plugin.
|
||||
|
||||
Arguments passed as `#[plugin=...]` or `#[plugin(...)]` are not interpreted by
|
||||
rustc itself. They are provided to the plugin through the `Registry`'s [`args`
|
||||
method](rustc/plugin/registry/struct.Registry.html#method.args).
|
||||
method](../rustc/plugin/registry/struct.Registry.html#method.args).
|
||||
|
||||
# Syntax extensions
|
||||
|
||||
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
|
||||
is the procedural macro. These are invoked the same way as [ordinary
|
||||
macros](guide-macros.html), but the expansion is performed by arbitrary Rust
|
||||
code that manipulates [syntax trees](syntax/ast/index.html) at
|
||||
macros](macros.html), but the expansion is performed by arbitrary Rust
|
||||
code that manipulates [syntax trees](../syntax/ast/index.html) at
|
||||
compile time.
|
||||
|
||||
Let's write a plugin
|
||||
@ -126,14 +126,13 @@ The advantages over a simple `fn(&str) -> uint` are:
|
||||
a way to define new literal syntax for any data type.
|
||||
|
||||
In addition to procedural macros, you can define new
|
||||
[`deriving`](reference.html#deriving)-like attributes and other kinds of
|
||||
[`deriving`](../reference.html#deriving)-like attributes and other kinds of
|
||||
extensions. See
|
||||
[`Registry::register_syntax_extension`](rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
|
||||
[`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
|
||||
and the [`SyntaxExtension`
|
||||
enum](http://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For
|
||||
a more involved macro example, see
|
||||
[`src/libregex_macros/lib.rs`](https://github.com/rust-lang/rust/blob/master/src/libregex_macros/lib.rs)
|
||||
in the Rust distribution.
|
||||
[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
|
||||
|
||||
|
||||
## Tips and tricks
|
||||
@ -147,7 +146,7 @@ variables of the same name (but different syntax contexts) are in play
|
||||
in the same scope. In this case `--pretty expanded,hygiene` will tell
|
||||
you about the syntax contexts.
|
||||
|
||||
You can use [`syntax::parse`](syntax/parse/index.html) to turn token trees into
|
||||
You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into
|
||||
higher-level syntax elements like expressions:
|
||||
|
||||
```ignore
|
||||
@ -163,23 +162,23 @@ Looking through [`libsyntax` parser
|
||||
code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
|
||||
will give you a feel for how the parsing infrastructure works.
|
||||
|
||||
Keep the [`Span`s](syntax/codemap/struct.Span.html) of
|
||||
Keep the [`Span`s](../syntax/codemap/struct.Span.html) of
|
||||
everything you parse, for better error reporting. You can wrap
|
||||
[`Spanned`](syntax/codemap/struct.Spanned.html) around
|
||||
[`Spanned`](../syntax/codemap/struct.Spanned.html) around
|
||||
your custom data structures.
|
||||
|
||||
Calling
|
||||
[`ExtCtxt::span_fatal`](syntax/ext/base/struct.ExtCtxt.html#method.span_fatal)
|
||||
[`ExtCtxt::span_fatal`](../syntax/ext/base/struct.ExtCtxt.html#method.span_fatal)
|
||||
will immediately abort compilation. It's better to instead call
|
||||
[`ExtCtxt::span_err`](syntax/ext/base/struct.ExtCtxt.html#method.span_err)
|
||||
[`ExtCtxt::span_err`](../syntax/ext/base/struct.ExtCtxt.html#method.span_err)
|
||||
and return
|
||||
[`DummyResult`](syntax/ext/base/struct.DummyResult.html),
|
||||
[`DummyResult`](../syntax/ext/base/struct.DummyResult.html),
|
||||
so that the compiler can continue and find further errors.
|
||||
|
||||
The example above produced an integer literal using
|
||||
[`AstBuilder::expr_uint`](syntax/ext/build/trait.AstBuilder.html#tymethod.expr_uint).
|
||||
[`AstBuilder::expr_uint`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_uint).
|
||||
As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
|
||||
[quasiquote macros](syntax/ext/quote/index.html). They are undocumented and
|
||||
[quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and
|
||||
very rough around the edges. However, the implementation may be a good
|
||||
starting point for an improved quasiquote as an ordinary plugin library.
|
||||
|
||||
@ -187,7 +186,7 @@ starting point for an improved quasiquote as an ordinary plugin library.
|
||||
# Lint plugins
|
||||
|
||||
Plugins can extend [Rust's lint
|
||||
infrastructure](reference.html#lint-check-attributes) with additional checks for
|
||||
infrastructure](../reference.html#lint-check-attributes) with additional checks for
|
||||
code style, safety, etc. You can see
|
||||
[`src/test/auxiliary/lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs)
|
||||
for a full example, the core of which is reproduced here:
|
||||
@ -236,11 +235,11 @@ foo.rs:4 fn lintme() { }
|
||||
The components of a lint plugin are:
|
||||
|
||||
* one or more `declare_lint!` invocations, which define static
|
||||
[`Lint`](rustc/lint/struct.Lint.html) structs;
|
||||
[`Lint`](../rustc/lint/struct.Lint.html) structs;
|
||||
|
||||
* a struct holding any state needed by the lint pass (here, none);
|
||||
|
||||
* a [`LintPass`](rustc/lint/trait.LintPass.html)
|
||||
* a [`LintPass`](../rustc/lint/trait.LintPass.html)
|
||||
implementation defining how to check each syntax element. A single
|
||||
`LintPass` may call `span_lint` for several different `Lint`s, but should
|
||||
register them all through the `get_lints` method.
|
||||
@ -252,7 +251,7 @@ mostly use the same infrastructure as lint plugins, and provide examples of how
|
||||
to access type information.
|
||||
|
||||
Lints defined by plugins are controlled by the usual [attributes and compiler
|
||||
flags](reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or
|
||||
flags](../reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or
|
||||
`-A test-lint`. These identifiers are derived from the first argument to
|
||||
`declare_lint!`, with appropriate case and punctuation conversion.
|
||||
|
@ -409,7 +409,7 @@ test.rs:4 let y = &x;
|
||||
|
||||
As you might guess, this kind of analysis is complex for a human, and therefore
|
||||
hard for a computer, too! There is an entire [guide devoted to references, ownership,
|
||||
and lifetimes](guide-ownership.html) that goes into this topic in
|
||||
and lifetimes](ownership.html) that goes into this topic in
|
||||
great detail, so if you want the full details, check that out.
|
||||
|
||||
## Best practices
|
||||
@ -542,7 +542,7 @@ with some improvements:
|
||||
4. Rust enforces that no other writeable pointers alias to this heap memory,
|
||||
which means writing to an invalid pointer is not possible.
|
||||
|
||||
See the section on references or the [ownership guide](guide-ownership.html)
|
||||
See the section on references or the [ownership guide](ownership.html)
|
||||
for more detail on how lifetimes work.
|
||||
|
||||
Using boxes and references together is very common. For example:
|
||||
@ -780,6 +780,6 @@ Here's a quick rundown of Rust's pointer types:
|
||||
|
||||
# Related resources
|
||||
|
||||
* [API documentation for Box](std/boxed/index.html)
|
||||
* [Ownership guide](guide-ownership.html)
|
||||
* [API documentation for Box](../std/boxed/index.html)
|
||||
* [Ownership guide](ownership.html)
|
||||
* [Cyclone paper on regions](http://www.cs.umd.edu/projects/cyclone/papers/cyclone-regions.pdf), which inspired Rust's lifetime system
|
@ -1,565 +0,0 @@
|
||||
% The Rust References and Lifetimes Guide
|
||||
|
||||
# Introduction
|
||||
|
||||
References are one of the more flexible and powerful tools available in
|
||||
Rust. They can point anywhere: into the heap, stack, and even into the
|
||||
interior of another data structure. A reference is as flexible as a C pointer
|
||||
or C++ reference.
|
||||
|
||||
Unlike C and C++ compilers, the Rust compiler includes special static
|
||||
checks that ensure that programs use references safely.
|
||||
|
||||
Despite their complete safety, a reference's representation at runtime
|
||||
is the same as that of an ordinary pointer in a C program. They introduce zero
|
||||
overhead. The compiler does all safety checks at compile time.
|
||||
|
||||
Although references have rather elaborate theoretical underpinnings
|
||||
(e.g. region pointers), the core concepts will be familiar to anyone
|
||||
who has worked with C or C++. The best way to explain how they are
|
||||
used—and their limitations—is probably just to work through several examples.
|
||||
|
||||
# By example
|
||||
|
||||
References, sometimes known as *borrowed pointers*, are only valid for
|
||||
a limited duration. References never claim any kind of ownership
|
||||
over the data that they point to. Instead, they are used for cases
|
||||
where you would like to use data for a short time.
|
||||
|
||||
Consider a simple struct type `Point`:
|
||||
|
||||
~~~
|
||||
struct Point {x: f64, y: f64}
|
||||
~~~
|
||||
|
||||
We can use this simple definition to allocate points in many different ways. For
|
||||
example, in this code, each of these local variables contains a point,
|
||||
but allocated in a different place:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
|
||||
let on_the_heap : Box<Point> = box Point {x: 7.0, y: 9.0};
|
||||
~~~
|
||||
|
||||
Suppose we wanted to write a procedure that computed the distance between any
|
||||
two points, no matter where they were stored. One option is to define a function
|
||||
that takes two arguments of type `Point`—that is, it takes the points by value.
|
||||
But if we define it this way, calling the function will cause the points to be
|
||||
copied. For points, this is probably not so bad, but often copies are
|
||||
expensive. So we'd like to define a function that takes the points just as
|
||||
a reference.
|
||||
|
||||
~~~
|
||||
# use std::num::Float;
|
||||
# struct Point {x: f64, y: f64}
|
||||
# fn sqrt(f: f64) -> f64 { 0.0 }
|
||||
fn compute_distance(p1: &Point, p2: &Point) -> f64 {
|
||||
let x_d = p1.x - p2.x;
|
||||
let y_d = p1.y - p2.y;
|
||||
(x_d * x_d + y_d * y_d).sqrt()
|
||||
}
|
||||
~~~
|
||||
|
||||
Now we can call `compute_distance()`:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
|
||||
# let on_the_heap : Box<Point> = box Point{x: 7.0, y: 9.0};
|
||||
# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
|
||||
compute_distance(&on_the_stack, &*on_the_heap);
|
||||
~~~
|
||||
|
||||
Here, the `&` operator takes the address of the variable
|
||||
`on_the_stack`; this is because `on_the_stack` has the type `Point`
|
||||
(that is, a struct value) and we have to take its address to get a
|
||||
value. We also call this _borrowing_ the local variable
|
||||
`on_the_stack`, because we have created an alias: that is, another
|
||||
name for the same data.
|
||||
|
||||
Likewise, in the case of `on_the_heap`,
|
||||
the `&` operator is used in conjunction with the `*` operator
|
||||
to take a reference to the contents of the box.
|
||||
|
||||
Whenever a caller lends data to a callee, there are some limitations on what
|
||||
the caller can do with the original. For example, if the contents of a
|
||||
variable have been lent out, you cannot send that variable to another task. In
|
||||
addition, the compiler will reject any code that might cause the borrowed
|
||||
value to be freed or overwrite its component fields with values of different
|
||||
types (I'll get into what kinds of actions those are shortly). This rule
|
||||
should make intuitive sense: you must wait for a borrower to return the value
|
||||
that you lent it (that is, wait for the reference to go out of scope)
|
||||
before you can make full use of it again.
|
||||
|
||||
# Other uses for the & operator
|
||||
|
||||
In the previous example, the value `on_the_stack` was defined like so:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
let on_the_stack: Point = Point {x: 3.0, y: 4.0};
|
||||
~~~
|
||||
|
||||
This declaration means that code can only pass `Point` by value to other
|
||||
functions. As a consequence, we had to explicitly take the address of
|
||||
`on_the_stack` to get a reference. Sometimes however it is more
|
||||
convenient to move the & operator into the definition of `on_the_stack`:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
let on_the_stack2: &Point = &Point {x: 3.0, y: 4.0};
|
||||
~~~
|
||||
|
||||
Applying `&` to an rvalue (non-assignable location) is just a convenient
|
||||
shorthand for creating a temporary and taking its address. A more verbose
|
||||
way to write the same code is:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
let tmp = Point {x: 3.0, y: 4.0};
|
||||
let on_the_stack2 : &Point = &tmp;
|
||||
~~~
|
||||
|
||||
# Taking the address of fields
|
||||
|
||||
The `&` operator is not limited to taking the address of
|
||||
local variables. It can also take the address of fields or
|
||||
individual array elements. For example, consider this type definition
|
||||
for `Rectangle`:
|
||||
|
||||
~~~
|
||||
struct Point {x: f64, y: f64} // as before
|
||||
struct Size {w: f64, h: f64} // as before
|
||||
struct Rectangle {origin: Point, size: Size}
|
||||
~~~
|
||||
|
||||
Now, as before, we can define rectangles in a few different ways:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
# struct Size {w: f64, h: f64} // as before
|
||||
# struct Rectangle {origin: Point, size: Size}
|
||||
let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
let rect_heap = box Rectangle {origin: Point {x: 5.0, y: 6.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
~~~
|
||||
|
||||
In each case, we can extract out individual subcomponents with the `&`
|
||||
operator. For example, I could write:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64} // as before
|
||||
# struct Size {w: f64, h: f64} // as before
|
||||
# struct Rectangle {origin: Point, size: Size}
|
||||
# let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0}, size: Size {w: 3.0, h: 4.0}};
|
||||
# let rect_heap = box Rectangle {origin: Point {x: 5.0, y: 6.0}, size: Size {w: 3.0, h: 4.0}};
|
||||
# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
|
||||
compute_distance(&rect_stack.origin, &rect_heap.origin);
|
||||
~~~
|
||||
|
||||
which would borrow the field `origin` from the rectangle on the stack
|
||||
as well as from the owned box, and then compute the distance between them.
|
||||
|
||||
# Lifetimes
|
||||
|
||||
We’ve seen a few examples of borrowing data. To this point, we’ve glossed
|
||||
over issues of safety. As stated in the introduction, at runtime a reference
|
||||
is simply a pointer, nothing more. Therefore, avoiding C's problems with
|
||||
dangling pointers requires a compile-time safety check.
|
||||
|
||||
The basis for the check is the notion of _lifetimes_. A lifetime is a
|
||||
static approximation of the span of execution during which the pointer
|
||||
is valid: it always corresponds to some expression or block within the
|
||||
program.
|
||||
|
||||
The compiler will only allow a borrow *if it can guarantee that the data will
|
||||
not be reassigned or moved for the lifetime of the pointer*. This does not
|
||||
necessarily mean that the data is stored in immutable memory. For example,
|
||||
the following function is legal:
|
||||
|
||||
~~~
|
||||
# fn some_condition() -> bool { true }
|
||||
# struct Foo { f: int }
|
||||
fn example3() -> int {
|
||||
let mut x = box Foo {f: 3};
|
||||
if some_condition() {
|
||||
let y = &x.f; // -+ L
|
||||
return *y; // |
|
||||
} // -+
|
||||
x = box Foo {f: 4};
|
||||
// ...
|
||||
# return 0;
|
||||
}
|
||||
~~~
|
||||
|
||||
Here, the interior of the variable `x` is being borrowed
|
||||
and `x` is declared as mutable. However, the compiler can prove that
|
||||
`x` is not assigned anywhere in the lifetime L of the variable
|
||||
`y`. Therefore, it accepts the function, even though `x` is mutable
|
||||
and in fact is mutated later in the function.
|
||||
|
||||
It may not be clear why we are so concerned about mutating a borrowed
|
||||
variable. The reason is that the runtime system frees any box
|
||||
_as soon as its owning reference changes or goes out of
|
||||
scope_. Therefore, a program like this is illegal (and would be
|
||||
rejected by the compiler):
|
||||
|
||||
~~~ {.ignore}
|
||||
fn example3() -> int {
|
||||
let mut x = box X {f: 3};
|
||||
let y = &x.f;
|
||||
x = box X {f: 4}; // Error reported here.
|
||||
*y
|
||||
}
|
||||
~~~
|
||||
|
||||
To make this clearer, consider this diagram showing the state of
|
||||
memory immediately before the re-assignment of `x`:
|
||||
|
||||
~~~ {.text}
|
||||
Stack Exchange Heap
|
||||
|
||||
x +-------------+
|
||||
| box {f:int} | ----+
|
||||
y +-------------+ |
|
||||
| &int | ----+
|
||||
+-------------+ | +---------+
|
||||
+--> | f: 3 |
|
||||
+---------+
|
||||
~~~
|
||||
|
||||
Once the reassignment occurs, the memory will look like this:
|
||||
|
||||
~~~ {.text}
|
||||
Stack Exchange Heap
|
||||
|
||||
x +-------------+ +---------+
|
||||
| box {f:int} | -------> | f: 4 |
|
||||
y +-------------+ +---------+
|
||||
| &int | ----+
|
||||
+-------------+ | +---------+
|
||||
+--> | (freed) |
|
||||
+---------+
|
||||
~~~
|
||||
|
||||
Here you can see that the variable `y` still points at the old `f`
|
||||
property of Foo, which has been freed.
|
||||
|
||||
In fact, the compiler can apply the same kind of reasoning to any
|
||||
memory that is (uniquely) owned by the stack frame. So we could
|
||||
modify the previous example to introduce additional owned pointers
|
||||
and structs, and the compiler will still be able to detect possible
|
||||
mutations. This time, we'll use an analogy to illustrate the concept.
|
||||
|
||||
~~~ {.ignore}
|
||||
fn example3() -> int {
|
||||
struct House { owner: Box<Person> }
|
||||
struct Person { age: int }
|
||||
|
||||
let mut house = box House {
|
||||
owner: box Person {age: 30}
|
||||
};
|
||||
|
||||
let owner_age = &house.owner.age;
|
||||
house = box House {owner: box Person {age: 40}}; // Error reported here.
|
||||
house.owner = box Person {age: 50}; // Error reported here.
|
||||
*owner_age
|
||||
}
|
||||
~~~
|
||||
|
||||
In this case, two errors are reported, one when the variable `house` is
|
||||
modified and another when `house.owner` is modified. Either modification would
|
||||
invalidate the pointer `owner_age`.
|
||||
|
||||
# Borrowing and enums
|
||||
|
||||
The previous example showed that the type system forbids any mutations
|
||||
of owned boxed values while they are being borrowed. In general, the type
|
||||
system also forbids borrowing a value as mutable if it is already being
|
||||
borrowed - either as a mutable reference or an immutable one. This restriction
|
||||
prevents pointers from pointing into freed memory. There is one other
|
||||
case where the compiler must be very careful to ensure that pointers
|
||||
remain valid: pointers into the interior of an `enum`.
|
||||
|
||||
Let’s look at the following `shape` type that can represent both rectangles
|
||||
and circles:
|
||||
|
||||
~~~
|
||||
struct Point {x: f64, y: f64}; // as before
|
||||
struct Size {w: f64, h: f64}; // as before
|
||||
enum Shape {
|
||||
Circle(Point, f64), // origin, radius
|
||||
Rectangle(Point, Size) // upper-left, dimensions
|
||||
}
|
||||
~~~
|
||||
|
||||
Now we might write a function to compute the area of a shape. This
|
||||
function takes a reference to a shape, to avoid the need for
|
||||
copying.
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
fn compute_area(shape: &Shape) -> f64 {
|
||||
match *shape {
|
||||
Shape::Circle(_, radius) => std::f64::consts::PI * radius * radius,
|
||||
Shape::Rectangle(_, ref size) => size.w * size.h
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
The first case matches against circles. Here, the pattern extracts the
|
||||
radius from the shape variant and the action uses it to compute the
|
||||
area of the circle.
|
||||
|
||||
The second match is more interesting. Here we match against a
|
||||
rectangle and extract its size: but rather than copy the `size`
|
||||
struct, we use a by-reference binding to create a pointer to it. In
|
||||
other words, a pattern binding like `ref size` binds the name `size`
|
||||
to a pointer of type `&size` into the _interior of the enum_.
|
||||
|
||||
To make this more clear, let's look at a diagram of memory layout in
|
||||
the case where `shape` points at a rectangle:
|
||||
|
||||
~~~ {.text}
|
||||
Stack Memory
|
||||
|
||||
+-------+ +---------------+
|
||||
| shape | ------> | rectangle( |
|
||||
+-------+ | {x: f64, |
|
||||
| size | -+ | y: f64}, |
|
||||
+-------+ +----> | {w: f64, |
|
||||
| h: f64}) |
|
||||
+---------------+
|
||||
~~~
|
||||
|
||||
Here you can see that rectangular shapes are composed of five words of
|
||||
memory. The first is a tag indicating which variant this enum is
|
||||
(`rectangle`, in this case). The next two words are the `x` and `y`
|
||||
fields for the point and the remaining two are the `w` and `h` fields
|
||||
for the size. The binding `size` is then a pointer into the inside of
|
||||
the shape.
|
||||
|
||||
Perhaps you can see where the danger lies: if the shape were somehow
|
||||
to be reassigned, perhaps to a circle, then although the memory used
|
||||
to store that shape value would still be valid, _it would have a
|
||||
different type_! The following diagram shows what memory would look
|
||||
like if code overwrote `shape` with a circle:
|
||||
|
||||
~~~ {.text}
|
||||
Stack Memory
|
||||
|
||||
+-------+ +---------------+
|
||||
| shape | ------> | circle( |
|
||||
+-------+ | {x: f64, |
|
||||
| size | -+ | y: f64}, |
|
||||
+-------+ +----> | f64) |
|
||||
| |
|
||||
+---------------+
|
||||
~~~
|
||||
|
||||
As you can see, the `size` pointer would be pointing at a `f64`
|
||||
instead of a struct. This is not good: dereferencing the second field
|
||||
of a `f64` as if it were a struct with two fields would be a memory
|
||||
safety violation.
|
||||
|
||||
So, in fact, for every `ref` binding, the compiler will impose the
|
||||
same rules as the ones we saw for borrowing the interior of an owned
|
||||
box: it must be able to guarantee that the `enum` will not be
|
||||
overwritten for the duration of the borrow. In fact, the compiler
|
||||
would accept the example we gave earlier. The example is safe because
|
||||
the shape pointer has type `&Shape`, which means "reference to
|
||||
immutable memory containing a `shape`". If, however, the type of that
|
||||
pointer were `&mut Shape`, then the ref binding would be ill-typed.
|
||||
Just as with owned boxes, the compiler will permit `ref` bindings
|
||||
into data owned by the stack frame even if the data are mutable,
|
||||
but otherwise it requires that the data reside in immutable memory.
|
||||
|
||||
# Returning references
|
||||
|
||||
So far, all of the examples we have looked at, use references in a
|
||||
“downward” direction. That is, a method or code block creates a
|
||||
reference, then uses it within the same scope. It is also
|
||||
possible to return references as the result of a function, but
|
||||
as we'll see, doing so requires some explicit annotation.
|
||||
|
||||
We could write a subroutine like this:
|
||||
|
||||
~~~
|
||||
struct Point {x: f64, y: f64}
|
||||
fn get_x<'r>(p: &'r Point) -> &'r f64 { &p.x }
|
||||
~~~
|
||||
|
||||
Here, the function `get_x()` returns a pointer into the structure it
|
||||
was given. The type of the parameter (`&'r Point`) and return type
|
||||
(`&'r f64`) both use a new syntactic form that we have not seen so
|
||||
far. Here the identifier `r` names the lifetime of the pointer
|
||||
explicitly. So in effect, this function declares that it takes a
|
||||
pointer with lifetime `r` and returns a pointer with that same
|
||||
lifetime.
|
||||
|
||||
In general, it is only possible to return references if they
|
||||
are derived from a parameter to the procedure. In that case, the
|
||||
pointer result will always have the same lifetime as one of the
|
||||
parameters; named lifetimes indicate which parameter that
|
||||
is.
|
||||
|
||||
In the previous code samples, function parameter types did not include a
|
||||
lifetime name. The compiler simply creates a fresh name for the lifetime
|
||||
automatically: that is, the lifetime name is guaranteed to refer to a distinct
|
||||
lifetime from the lifetimes of all other parameters.
|
||||
|
||||
Named lifetimes that appear in function signatures are conceptually
|
||||
the same as the other lifetimes we have seen before, but they are a bit
|
||||
abstract: they don’t refer to a specific expression within `get_x()`,
|
||||
but rather to some expression within the *caller of `get_x()`*. The
|
||||
lifetime `r` is actually a kind of *lifetime parameter*: it is defined
|
||||
by the caller to `get_x()`, just as the value for the parameter `p` is
|
||||
defined by that caller.
|
||||
|
||||
In any case, whatever the lifetime of `r` is, the pointer produced by
|
||||
`&p.x` always has the same lifetime as `p` itself: a pointer to a
|
||||
field of a struct is valid as long as the struct is valid. Therefore,
|
||||
the compiler accepts the function `get_x()`.
|
||||
|
||||
In general, if you borrow a struct or box to create a
|
||||
reference, it will only be valid within the function
|
||||
and cannot be returned. This is why the typical way to return references
|
||||
is to take references as input (the only other case in
|
||||
which it can be legal to return a reference is if it
|
||||
points at a static constant).
|
||||
|
||||
# Named lifetimes
|
||||
|
||||
Lifetimes can be named and referenced. For example, the special lifetime
|
||||
`'static`, which does not go out of scope, can be used to create global
|
||||
variables and communicate between tasks (see the manual for use cases).
|
||||
|
||||
## Parameter Lifetimes
|
||||
|
||||
Named lifetimes allow for grouping of parameters by lifetime.
|
||||
For example, consider this function:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
# fn compute_area(shape: &Shape) -> f64 { 0.0 }
|
||||
fn select<'r, T>(shape: &'r Shape, threshold: f64,
|
||||
a: &'r T, b: &'r T) -> &'r T {
|
||||
if compute_area(shape) > threshold {a} else {b}
|
||||
}
|
||||
~~~
|
||||
|
||||
This function takes three references and assigns each the same
|
||||
lifetime `r`. In practice, this means that, in the caller, the
|
||||
lifetime `r` will be the *intersection of the lifetime of the three
|
||||
region parameters*. This may be overly conservative, as in this
|
||||
example:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
# fn compute_area(shape: &Shape) -> f64 { 0.0 }
|
||||
# fn select<'r, T>(shape: &Shape, threshold: f64,
|
||||
# a: &'r T, b: &'r T) -> &'r T {
|
||||
# if compute_area(shape) > threshold {a} else {b}
|
||||
# }
|
||||
// -+ r
|
||||
fn select_based_on_unit_circle<'r, T>( // |-+ B
|
||||
threshold: f64, a: &'r T, b: &'r T) -> &'r T { // | |
|
||||
// | |
|
||||
let shape = Shape::Circle(Point {x: 0., y: 0.}, 1.); // | |
|
||||
select(&shape, threshold, a, b) // | |
|
||||
} // |-+
|
||||
// -+
|
||||
~~~
|
||||
|
||||
In this call to `select()`, the lifetime of the first parameter shape
|
||||
is B, the function body. Both of the second two parameters `a` and `b`
|
||||
share the same lifetime, `r`, which is a lifetime parameter of
|
||||
`select_based_on_unit_circle()`. The caller will infer the
|
||||
intersection of these two lifetimes as the lifetime of the returned
|
||||
value, and hence the return value of `select()` will be assigned a
|
||||
lifetime of B. This will in turn lead to a compilation error, because
|
||||
`select_based_on_unit_circle()` is supposed to return a value with the
|
||||
lifetime `r`.
|
||||
|
||||
To address this, we can modify the definition of `select()` to
|
||||
distinguish the lifetime of the first parameter from the lifetime of
|
||||
the latter two. After all, the first parameter is not being
|
||||
returned. Here is how the new `select()` might look:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
# fn compute_area(shape: &Shape) -> f64 { 0.0 }
|
||||
fn select<'r, 'tmp, T>(shape: &'tmp Shape, threshold: f64,
|
||||
a: &'r T, b: &'r T) -> &'r T {
|
||||
if compute_area(shape) > threshold {a} else {b}
|
||||
}
|
||||
~~~
|
||||
|
||||
Here you can see that `shape`'s lifetime is now named `tmp`. The
|
||||
parameters `a`, `b`, and the return value all have the lifetime `r`.
|
||||
However, since the lifetime `tmp` is not returned, it would be more
|
||||
concise to just omit the named lifetime for `shape` altogether:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
# fn compute_area(shape: &Shape) -> f64 { 0.0 }
|
||||
fn select<'r, T>(shape: &Shape, threshold: f64,
|
||||
a: &'r T, b: &'r T) -> &'r T {
|
||||
if compute_area(shape) > threshold {a} else {b}
|
||||
}
|
||||
~~~
|
||||
|
||||
This is equivalent to the previous definition.
|
||||
|
||||
## Labeled Control Structures
|
||||
|
||||
Named lifetime notation can also be used to control the flow of execution:
|
||||
|
||||
~~~
|
||||
'h: for i in range(0u, 10) {
|
||||
'g: loop {
|
||||
if i % 2 == 0 { continue 'h; }
|
||||
if i == 9 { break 'h; }
|
||||
break 'g;
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
> *Note:* Labelled breaks are not currently supported within `while` loops.
|
||||
|
||||
Named labels are hygienic and can be used safely within macros.
|
||||
See the macros guide section on hygiene for more details.
|
||||
|
||||
# Conclusion
|
||||
|
||||
So there you have it: a (relatively) brief tour of the lifetime
|
||||
system. For more details, we refer to the (yet to be written) reference
|
||||
document on references, which will explain the full notation
|
||||
and give more examples.
|
@ -1,4 +1,4 @@
|
||||
# Standard Input
|
||||
% Standard Input
|
||||
|
||||
Getting input from the keyboard is pretty easy, but uses some things
|
||||
we haven't seen before. Here's a simple program that reads some input,
|
@ -1,4 +1,4 @@
|
||||
# Strings
|
||||
% Strings
|
||||
|
||||
Strings are an important concept for any programmer to master. Rust's string
|
||||
handling system is a bit different from other languages, due to its systems
|
@ -369,7 +369,7 @@ Unlike `spawn`, the function spawned using `try` may return a value, which
|
||||
child thread terminates successfully, `try` will return an `Ok` result; if the
|
||||
child thread panics, `try` will return an `Error` result.
|
||||
|
||||
[`Result`]: std/result/index.html
|
||||
[`Result`]: ../std/result/index.html
|
||||
|
||||
> *Note:* A panicked thread does not currently produce a useful error
|
||||
> value (`try` always returns `Err(())`). In the
|
@ -12,7 +12,7 @@ block which allows the programmer to dodge some of the compiler's
|
||||
checks and do a wide range of operations, such as:
|
||||
|
||||
- dereferencing [raw pointers](#raw-pointers)
|
||||
- calling a function via FFI ([covered by the FFI guide](guide-ffi.html))
|
||||
- calling a function via FFI ([covered by the FFI guide](ffi.html))
|
||||
- casting between types bitwise (`transmute`, aka "reinterpret cast")
|
||||
- [inline assembly](#inline-assembly)
|
||||
|
||||
@ -37,7 +37,7 @@ build safe interfaces.
|
||||
## References
|
||||
|
||||
One of Rust's biggest features is memory safety. This is achieved in
|
||||
part via [the ownership system](guide-ownership.html), which is how the
|
||||
part via [the ownership system](ownership.html), which is how the
|
||||
compiler can guarantee that every `&` reference is always valid, and,
|
||||
for example, never pointing to freed memory.
|
||||
|
||||
@ -504,7 +504,7 @@ shouldn't get triggered.
|
||||
The second of these three functions, `eh_personality`, is used by the
|
||||
failure mechanisms of the compiler. This is often mapped to GCC's
|
||||
personality function (see the
|
||||
[libstd implementation](std/rt/unwind/index.html) for more
|
||||
[libstd implementation](../std/rt/unwind/index.html) for more
|
||||
information), but crates which do not trigger a panic can be assured
|
||||
that this function is never called. The final function, `panic_fmt`, is
|
||||
also used by the failure mechanisms of the compiler.
|
||||
@ -517,7 +517,7 @@ also used by the failure mechanisms of the compiler.
|
||||
With the above techniques, we've got a bare-metal executable running some Rust
|
||||
code. There is a good deal of functionality provided by the standard library,
|
||||
however, that is necessary to be productive in Rust. If the standard library is
|
||||
not sufficient, then [libcore](core/index.html) is designed to be used
|
||||
not sufficient, then [libcore](../core/index.html) is designed to be used
|
||||
instead.
|
||||
|
||||
The core library has very few dependencies and is much more portable than the
|
@ -1,4 +1,4 @@
|
||||
# Variable bindings
|
||||
% Variable bindings
|
||||
|
||||
The first thing we'll learn about are 'variable bindings.' They look like this:
|
||||
|
||||
@ -170,5 +170,5 @@ 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:
|
||||
available](../std/fmt/index.html). For now, we'll just stick to the default:
|
||||
integers aren't very complicated to print.
|
@ -29,8 +29,8 @@ pub struct Book {
|
||||
/// A depth-first iterator over a book.
|
||||
pub struct BookItems<'a> {
|
||||
cur_items: &'a [BookItem],
|
||||
cur_idx: uint,
|
||||
stack: Vec<(&'a [BookItem], uint)>,
|
||||
cur_idx: usize,
|
||||
stack: Vec<(&'a [BookItem], usize)>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for BookItems<'a> {
|
||||
@ -80,7 +80,7 @@ impl Book {
|
||||
pub fn parse_summary<R: Reader>(input: R, src: &Path) -> Result<Book, Vec<String>> {
|
||||
fn collapse(stack: &mut Vec<BookItem>,
|
||||
top_items: &mut Vec<BookItem>,
|
||||
to_level: uint) {
|
||||
to_level: usize) {
|
||||
loop {
|
||||
if stack.len() < to_level { return }
|
||||
if stack.len() == 1 {
|
||||
@ -141,7 +141,7 @@ pub fn parse_summary<R: Reader>(input: R, src: &Path) -> Result<Book, Vec<String
|
||||
};
|
||||
let level = cap.name("indent").unwrap().chars().map(|c| {
|
||||
match c {
|
||||
' ' => 1u,
|
||||
' ' => 1us,
|
||||
'\t' => 4,
|
||||
_ => unreachable!()
|
||||
}
|
||||
|
11
src/rustbook/build.rs
Executable file → Normal file
11
src/rustbook/build.rs
Executable file → Normal file
@ -130,8 +130,8 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
|
||||
];
|
||||
let output_result = rustdoc::main_args(rustdoc_args);
|
||||
if output_result != 0 {
|
||||
|
||||
let message = format!("Could not execute `rustdoc`: {}", output_result);
|
||||
let message = format!("Could not execute `rustdoc` with {:?}: {}",
|
||||
rustdoc_args, output_result);
|
||||
return Err(box message as Box<Error>);
|
||||
}
|
||||
}
|
||||
@ -172,12 +172,13 @@ impl Subcommand for Build {
|
||||
match book::parse_summary(summary, &src) {
|
||||
Ok(book) => {
|
||||
// execute rustdoc on the whole book
|
||||
let _ = render(&book, &tgt).map_err(|err| {
|
||||
try!(render(&book, &tgt).map_err(|err| {
|
||||
term.err(&format!("error: {}", err.description())[]);
|
||||
err.detail().map(|detail| {
|
||||
term.err(&format!("detail: {}", detail)[]);
|
||||
})
|
||||
});
|
||||
});
|
||||
err
|
||||
}))
|
||||
}
|
||||
Err(errors) => {
|
||||
for err in errors.into_iter() {
|
||||
|
@ -56,6 +56,12 @@ impl Error for String {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Error for Box<Error + 'a> {
|
||||
fn description(&self) -> &str { (**self).description() }
|
||||
fn detail(&self) -> Option<&str> { (**self).detail() }
|
||||
fn cause(&self) -> Option<&Error> { (**self).cause() }
|
||||
}
|
||||
|
||||
impl FromError<()> for () {
|
||||
fn from_err(_: ()) -> () { () }
|
||||
}
|
||||
|
0
src/rustbook/main.rs
Executable file → Normal file
0
src/rustbook/main.rs
Executable file → Normal file
@ -11,6 +11,7 @@
|
||||
//! An abstraction of the terminal. Eventually, provide color and
|
||||
//! verbosity support. For now, just a wrapper around stdout/stderr.
|
||||
|
||||
use std::os;
|
||||
use std::io::stdio;
|
||||
|
||||
pub struct Term {
|
||||
@ -27,5 +28,6 @@ impl Term {
|
||||
pub fn err(&mut self, msg: &str) {
|
||||
// swallow any errors
|
||||
let _ = self.err.write_line(msg);
|
||||
os::set_exit_status(101);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user