2012-10-07 00:47:26 -05:00
|
|
|
|
% The Rust Language Tutorial
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
# Introduction
|
|
|
|
|
|
2012-09-22 19:57:30 -05:00
|
|
|
|
Rust is a programming language with a focus on type safety, memory
|
|
|
|
|
safety, concurrency and performance. It is intended for writing
|
2012-10-10 21:05:13 -05:00
|
|
|
|
large-scale, high-performance software that is free from several
|
2012-09-22 19:57:30 -05:00
|
|
|
|
classes of common errors. Rust has a sophisticated memory model that
|
|
|
|
|
encourages efficient data structures and safe concurrency patterns,
|
|
|
|
|
forbidding invalid memory accesses that would otherwise cause
|
|
|
|
|
segmentation faults. It is statically typed and compiled ahead of
|
|
|
|
|
time.
|
2012-07-06 14:14:32 -05:00
|
|
|
|
|
2012-07-22 21:12:51 -05:00
|
|
|
|
As a multi-paradigm language, Rust supports writing code in
|
2012-09-22 19:57:30 -05:00
|
|
|
|
procedural, functional and object-oriented styles. Some of its
|
|
|
|
|
pleasant high-level features include:
|
2012-07-06 14:14:32 -05:00
|
|
|
|
|
2012-10-06 22:23:38 -05:00
|
|
|
|
* **Type inference.** Type annotations on local variable declarations
|
|
|
|
|
are optional.
|
|
|
|
|
* **Safe task-based concurrency.** Rust's lightweight tasks do not share
|
2012-10-10 21:05:13 -05:00
|
|
|
|
memory, instead communicating through messages.
|
2012-10-06 22:23:38 -05:00
|
|
|
|
* **Higher-order functions.** Efficient and flexible closures provide
|
|
|
|
|
iteration and other control structures
|
|
|
|
|
* **Pattern matching and algebraic data types.** Pattern matching on
|
2012-10-10 21:05:13 -05:00
|
|
|
|
Rust's enumeration types (a more powerful version of C's enums,
|
|
|
|
|
similar to algebraic data types in functional languages) is a
|
|
|
|
|
compact and expressive way to encode program logic.
|
|
|
|
|
* **Polymorphism.** Rust has type-parametric functions and
|
2012-10-06 22:23:38 -05:00
|
|
|
|
types, type classes and OO-style interfaces.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 19:57:30 -05:00
|
|
|
|
## Scope
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 19:57:30 -05:00
|
|
|
|
This is an introductory tutorial for the Rust programming language. It
|
|
|
|
|
covers the fundamentals of the language, including the syntax, the
|
2012-10-07 00:23:16 -05:00
|
|
|
|
type system and memory model, generics, and modules. [Additional
|
2012-09-22 19:57:30 -05:00
|
|
|
|
tutorials](#what-next) cover specific language features in greater
|
|
|
|
|
depth.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 21:05:13 -05:00
|
|
|
|
This tutorial assumes that the reader is familiar with the basic concepts of
|
2012-09-22 19:57:30 -05:00
|
|
|
|
programming, and has programmed in one or more other languages
|
2012-10-10 21:05:13 -05:00
|
|
|
|
before. We will often compare Rust to other languages,
|
2012-09-22 19:57:30 -05:00
|
|
|
|
particularly those in the C family.
|
2012-07-03 19:48:08 -05:00
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
## Conventions
|
|
|
|
|
|
2012-10-10 21:05:13 -05:00
|
|
|
|
Throughout the tutorial, language keywords and identifiers defined in
|
|
|
|
|
example code are displayed in `code font`.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-01-19 23:22:05 -06:00
|
|
|
|
Code snippets are indented, and also shown in a monospaced font. Not
|
2012-01-19 05:51:20 -06:00
|
|
|
|
all snippets constitute whole programs. For brevity, we'll often show
|
|
|
|
|
fragments of programs that don't compile on their own. To try them
|
|
|
|
|
out, you might have to wrap them in `fn main() { ... }`, and make sure
|
2012-10-10 21:05:13 -05:00
|
|
|
|
they don't contain references to names that aren't actually defined.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 21:05:13 -05:00
|
|
|
|
> ***Warning:*** Rust is a language under ongoing development. Notes
|
2012-07-08 01:50:30 -05:00
|
|
|
|
> about potential changes to the language, implementation
|
|
|
|
|
> deficiencies, and other caveats appear offset in blockquotes.
|
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
# Getting started
|
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
The Rust compiler currently must be built from a [tarball], unless you
|
|
|
|
|
are on Windows, in which case using the [installer][win-exe] is
|
|
|
|
|
recommended.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
Since the Rust compiler is written in Rust, it must be built by
|
|
|
|
|
a precompiled "snapshot" version of itself (made in an earlier state
|
|
|
|
|
of development). As such, source builds require a connection to
|
|
|
|
|
the Internet, to fetch snapshots, and an OS that can execute the
|
|
|
|
|
available snapshot binaries.
|
2012-01-19 16:48:38 -06:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
Snapshot binaries are currently built and tested on several platforms:
|
2012-01-19 16:48:38 -06:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
* Windows (7, Server 2008 R2), x86 only
|
|
|
|
|
* Linux (various distributions), x86 and x86-64
|
2012-10-10 19:56:23 -05:00
|
|
|
|
* OSX 10.6 ("Snow Leopard") or greater, x86 and x86-64
|
2012-01-19 16:48:38 -06:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
You may find that other platforms work, but these are our "tier 1"
|
|
|
|
|
supported build environments that are most likely to work.
|
|
|
|
|
|
|
|
|
|
> ***Note:*** Windows users should read the detailed
|
2012-10-10 21:05:13 -05:00
|
|
|
|
> "[getting started][wiki-start]" notes on the wiki. Even when using
|
|
|
|
|
> the binary installer, the Windows build requires a MinGW installation,
|
|
|
|
|
> the precise details of which are not discussed here. Finally, `rustc` may
|
|
|
|
|
> need to be [referred to as `rustc.exe`][bug-3319]. It's a bummer, I
|
|
|
|
|
> know.
|
|
|
|
|
|
|
|
|
|
[bug-3319]: https://github.com/mozilla/rust/issues/3319
|
|
|
|
|
[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
|
2012-01-19 16:48:38 -06:00
|
|
|
|
|
|
|
|
|
To build from source you will also need the following prerequisite
|
|
|
|
|
packages:
|
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
* g++ 4.4 or clang++ 3.x
|
|
|
|
|
* python 2.6 or later (but not 3.x)
|
|
|
|
|
* perl 5.0 or later
|
|
|
|
|
* gnu make 3.81 or later
|
|
|
|
|
* curl
|
2012-01-19 16:48:38 -06:00
|
|
|
|
|
2012-10-10 21:05:13 -05:00
|
|
|
|
If you've fulfilled those prerequisites, something along these lines
|
|
|
|
|
should work.
|
2012-01-19 16:48:38 -06:00
|
|
|
|
|
2012-03-20 18:01:32 -05:00
|
|
|
|
~~~~ {.notrust}
|
2012-11-11 10:19:40 -06:00
|
|
|
|
$ curl -O http://dl.rust-lang.org/dist/rust-0.4.tar.gz
|
2012-09-15 20:55:06 -05:00
|
|
|
|
$ tar -xzf rust-0.4.tar.gz
|
|
|
|
|
$ cd rust-0.4
|
2012-01-19 16:48:38 -06:00
|
|
|
|
$ ./configure
|
|
|
|
|
$ make && make install
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-01-25 15:37:14 -06:00
|
|
|
|
You may need to use `sudo make install` if you do not normally have
|
2012-07-03 21:08:13 -05:00
|
|
|
|
permission to modify the destination directory. The install locations
|
|
|
|
|
can be adjusted by passing a `--prefix` argument to
|
2012-10-10 21:05:13 -05:00
|
|
|
|
`configure`. Various other options are also supported: pass `--help`
|
2012-07-03 21:08:13 -05:00
|
|
|
|
for more information on them.
|
2012-01-23 16:08:26 -06:00
|
|
|
|
|
2012-09-26 21:34:48 -05:00
|
|
|
|
When complete, `make install` will place several programs into
|
|
|
|
|
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
|
|
|
|
|
API-documentation tool, and `cargo`, the Rust package manager.
|
2012-01-19 16:48:38 -06:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
|
2012-09-15 20:55:06 -05:00
|
|
|
|
[tarball]: http://dl.rust-lang.org/dist/rust-0.4.tar.gz
|
2012-09-22 20:59:34 -05:00
|
|
|
|
[win-exe]: http://dl.rust-lang.org/dist/rust-0.4-install.exe
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
## Compiling your first program
|
|
|
|
|
|
|
|
|
|
Rust program files are, by convention, given the extension `.rs`. Say
|
|
|
|
|
we have a file `hello.rs` containing this program:
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-08-31 18:57:37 -05:00
|
|
|
|
fn main() {
|
2012-09-22 20:59:34 -05:00
|
|
|
|
io::println("hello? yes, this is rust");
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
If the Rust compiler was installed successfully, running `rustc
|
2012-09-22 20:59:34 -05:00
|
|
|
|
hello.rs` will produce an executable called `hello` (or `hello.exe` on
|
2012-10-07 00:57:40 -05:00
|
|
|
|
Windows) which, upon running, will likely do exactly what you expect.
|
2012-09-22 20:59:34 -05:00
|
|
|
|
|
2012-10-10 21:05:13 -05:00
|
|
|
|
The Rust compiler tries to provide useful information when it encounters an
|
|
|
|
|
error. If you introduce an error into the program (for example, by changing
|
|
|
|
|
`io::println` to some nonexistent function), and then compile it, you'll see
|
|
|
|
|
an error message like this:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-03-20 18:01:32 -05:00
|
|
|
|
~~~~ {.notrust}
|
2012-10-03 19:52:04 -05:00
|
|
|
|
hello.rs:2:4: 2:16 error: unresolved name: io::print_with_unicorns
|
|
|
|
|
hello.rs:2 io::print_with_unicorns("hello? yes, this is rust");
|
|
|
|
|
^~~~~~~~~~~~~~~~~~~~~~~
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
In its simplest form, a Rust program is a `.rs` file with some types
|
|
|
|
|
and functions defined in it. If it has a `main` function, it can be
|
|
|
|
|
compiled to an executable. Rust does not allow code that's not a
|
2012-10-10 21:05:13 -05:00
|
|
|
|
declaration to appear at the top level of the file: all statements must
|
2012-09-22 20:59:34 -05:00
|
|
|
|
live inside a function. Rust programs can also be compiled as
|
2012-10-05 21:51:36 -05:00
|
|
|
|
libraries, and included in other programs.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
## Editing Rust code
|
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
There are vim highlighting and indentation scripts in the Rust source
|
|
|
|
|
distribution under `src/etc/vim/`. There is an emacs mode under
|
|
|
|
|
`src/etc/emacs/` called `rust-mode`, but do read the instructions
|
|
|
|
|
included in that directory. In particular, if you are running emacs
|
|
|
|
|
24, then using emacs's internal package manager to install `rust-mode`
|
|
|
|
|
is the easiest way to keep it up to date. There is also a package for
|
|
|
|
|
Sublime Text 2, available both [standalone][sublime] and through
|
2012-10-03 19:52:04 -05:00
|
|
|
|
[Sublime Package Control][sublime-pkg], and support for Kate
|
|
|
|
|
under `src/etc/kate`.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-03 19:52:04 -05:00
|
|
|
|
There is ctags support via `src/etc/ctags.rust`, but many other
|
2012-10-10 21:05:13 -05:00
|
|
|
|
tools and editors are not yet supported. If you end up writing a Rust
|
2012-01-19 05:51:20 -06:00
|
|
|
|
mode for your favorite editor, let us know so that we can link to it.
|
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
[sublime]: http://github.com/dbp/sublime-rust
|
|
|
|
|
[sublime-pkg]: http://wbond.net/sublime_packages/package_control
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:40:12 -05:00
|
|
|
|
# Syntax basics
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
Assuming you've programmed in any C-family language (C++, Java,
|
2012-09-22 20:59:34 -05:00
|
|
|
|
JavaScript, C#, or PHP), Rust will feel familiar. Code is arranged
|
|
|
|
|
in blocks delineated by curly braces; there are control structures
|
2012-10-03 19:52:04 -05:00
|
|
|
|
for branching and looping, like the familiar `if` and `while`; function
|
2012-09-22 20:59:34 -05:00
|
|
|
|
calls are written `myfunc(arg1, arg2)`; operators are written the same
|
|
|
|
|
and mostly have the same precedence as in C; comments are again like C.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
The main surface difference to be aware of is that the condition at
|
|
|
|
|
the head of control structures like `if` and `while` do not require
|
2012-10-10 21:32:11 -05:00
|
|
|
|
parentheses, while their bodies *must* be wrapped in
|
|
|
|
|
braces. Single-statement, unbraced bodies are not allowed.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-23 01:11:24 -05:00
|
|
|
|
# fn recalibrate_universe() -> bool { true }
|
2012-01-19 05:51:20 -06:00
|
|
|
|
fn main() {
|
2012-09-23 01:11:24 -05:00
|
|
|
|
/* A simple loop */
|
|
|
|
|
loop {
|
|
|
|
|
// A tricky calculation
|
|
|
|
|
if recalibrate_universe() {
|
|
|
|
|
return;
|
2012-08-31 18:57:37 -05:00
|
|
|
|
}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
The `let` keyword introduces a local variable. Variables are immutable by
|
|
|
|
|
default. To introduce a local variable that you can re-assign later, use `let
|
|
|
|
|
mut` instead.
|
2012-09-22 20:59:34 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
let hi = "hi";
|
|
|
|
|
let mut count = 0;
|
|
|
|
|
|
|
|
|
|
while count < 10 {
|
|
|
|
|
io::println(hi);
|
|
|
|
|
count += 1;
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-03 19:52:04 -05:00
|
|
|
|
Although Rust can almost always infer the types of local variables, you
|
|
|
|
|
can specify a variable's type by following it with a colon, then the type
|
2012-10-11 22:13:04 -05:00
|
|
|
|
name.
|
2012-09-22 20:59:34 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-10-03 19:52:04 -05:00
|
|
|
|
let monster_size: float = 57.8;
|
2012-10-04 01:53:26 -05:00
|
|
|
|
let imaginary_size = monster_size * 10.0;
|
2012-10-03 19:52:04 -05:00
|
|
|
|
let monster_size: int = 50;
|
2012-09-22 20:59:34 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
Local variables may shadow earlier declarations, as in the previous example:
|
|
|
|
|
`monster_size` was first declared as a `float`, and then then a second
|
|
|
|
|
`monster_size` was declared as an int. If you were to actually compile this
|
|
|
|
|
example, though, the compiler will determine that the second `monster_size` is
|
|
|
|
|
unused and issue a warning (because this situation is likely to indicate a
|
|
|
|
|
programmer error). For occasions where unused variables are intentional, their
|
|
|
|
|
name may be prefixed with an underscore to silence the warning, like `let
|
|
|
|
|
_monster_size = 50;`.
|
2012-10-02 22:28:53 -05:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
Rust identifiers follow the same rules as C; they start with an alphabetic
|
|
|
|
|
character or an underscore, and after that may contain any sequence of
|
|
|
|
|
alphabetic characters, numbers, or underscores. The preferred style is to
|
|
|
|
|
begin function, variable, and module names with a lowercase letter, using
|
|
|
|
|
underscores where they help readability, while writing types in camel case.
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
let my_variable = 100;
|
2012-10-03 19:52:04 -05:00
|
|
|
|
type MyType = int; // some built-in types are _not_ camel case
|
2012-09-22 20:59:34 -05:00
|
|
|
|
~~~
|
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
## Expression syntax
|
|
|
|
|
|
|
|
|
|
Though it isn't apparent in all code, there is a fundamental
|
2012-10-03 19:52:04 -05:00
|
|
|
|
difference between Rust's syntax and predecessors like C.
|
|
|
|
|
Many constructs that are statements in C are expressions
|
2012-09-22 20:59:34 -05:00
|
|
|
|
in Rust, allowing code to be more concise. For example, you might
|
2012-08-31 18:57:37 -05:00
|
|
|
|
write a piece of code like this:
|
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
# let item = "salad";
|
|
|
|
|
let price;
|
|
|
|
|
if item == "salad" {
|
|
|
|
|
price = 3.50;
|
|
|
|
|
} else if item == "muffin" {
|
|
|
|
|
price = 2.25;
|
|
|
|
|
} else {
|
|
|
|
|
price = 2.00;
|
|
|
|
|
}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-08-31 18:57:37 -05:00
|
|
|
|
But, in Rust, you don't have to repeat the name `price`:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-08-31 18:57:37 -05:00
|
|
|
|
# let item = "salad";
|
2012-10-03 19:52:04 -05:00
|
|
|
|
let price =
|
|
|
|
|
if item == "salad" {
|
|
|
|
|
3.50
|
|
|
|
|
} else if item == "muffin" {
|
|
|
|
|
2.25
|
|
|
|
|
} else {
|
|
|
|
|
2.00
|
|
|
|
|
};
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
Both pieces of code are exactly equivalent: they assign a value to
|
2012-10-03 19:52:04 -05:00
|
|
|
|
`price` depending on the condition that holds. Note that there
|
2012-10-10 21:32:11 -05:00
|
|
|
|
are no semicolons in the blocks of the second snippet. This is
|
|
|
|
|
important: the lack of a semicolon after the last statement in a
|
2012-09-22 20:59:34 -05:00
|
|
|
|
braced block gives the whole block the value of that last expression.
|
2012-08-31 18:57:37 -05:00
|
|
|
|
|
2012-10-04 00:18:46 -05:00
|
|
|
|
Put another way, the semicolon in Rust *ignores the value of an expression*.
|
|
|
|
|
Thus, if the branches of the `if` had looked like `{ 4; }`, the above example
|
|
|
|
|
would simply assign `()` (nil or void) to `price`. But without the semicolon, each
|
|
|
|
|
branch has a different value, and `price` gets the value of the branch that
|
|
|
|
|
was taken.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
In short, everything that's not a declaration (declarations are `let` for
|
|
|
|
|
variables, `fn` for functions, and any top-level named items such as
|
|
|
|
|
[traits](#traits), [enum types](#enums), and [constants](#constants)) is an
|
|
|
|
|
expression, including function bodies.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-22 20:59:34 -05:00
|
|
|
|
fn is_four(x: int) -> bool {
|
|
|
|
|
// No need for a return statement. The result of the expression
|
|
|
|
|
// is used as the return value.
|
|
|
|
|
x == 4
|
|
|
|
|
}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
If all those things are expressions, you might conclude that you have
|
|
|
|
|
to add a terminating semicolon after *every* statement, even ones that
|
|
|
|
|
are not traditionally terminated with a semicolon in C (like `while`).
|
|
|
|
|
That is not the case, though. Expressions that end in a block only
|
|
|
|
|
need a semicolon if that block contains a trailing expression. `while`
|
|
|
|
|
loops do not allow trailing expressions, and `if` statements tend to
|
|
|
|
|
only have a trailing expression when you want to use their value for
|
2012-09-22 20:59:34 -05:00
|
|
|
|
something—in which case you'll have embedded it in a bigger statement.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
~~~
|
|
|
|
|
# fn foo() -> bool { true }
|
|
|
|
|
# fn bar() -> bool { true }
|
|
|
|
|
# fn baz() -> bool { true }
|
2012-10-10 21:32:11 -05:00
|
|
|
|
// `let` is not an expression, so it is semicolon-terminated;
|
2012-09-22 20:59:34 -05:00
|
|
|
|
let x = foo();
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
// When used in statement position, bracy expressions do not
|
|
|
|
|
// usually need to be semicolon terminated
|
|
|
|
|
if x {
|
|
|
|
|
bar();
|
|
|
|
|
} else {
|
|
|
|
|
baz();
|
|
|
|
|
} // No semi-colon
|
|
|
|
|
|
|
|
|
|
// Although, if `bar` and `baz` have non-nil return types, and
|
|
|
|
|
// we try to use them as the tail expressions, rustc will
|
|
|
|
|
// make us terminate the expression.
|
|
|
|
|
if x {
|
|
|
|
|
bar()
|
|
|
|
|
} else {
|
|
|
|
|
baz()
|
|
|
|
|
}; // Semi-colon to ignore non-nil block type
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 20:59:34 -05:00
|
|
|
|
// An `if` embedded in `let` again requires a semicolon to terminate
|
|
|
|
|
// the `let` statement
|
|
|
|
|
let y = if x { foo() } else { bar() };
|
|
|
|
|
~~~
|
2012-07-07 20:00:16 -05:00
|
|
|
|
|
2012-10-03 22:06:54 -05:00
|
|
|
|
This may sound intricate, but it is super-useful and will grow on you.
|
2012-07-07 20:00:16 -05:00
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
## Types
|
|
|
|
|
|
2012-10-04 19:33:06 -05:00
|
|
|
|
The basic types include the usual boolean, integral, and floating-point types.
|
2012-09-22 23:14:58 -05:00
|
|
|
|
|
|
|
|
|
------------------------- -----------------------------------------------
|
2012-10-10 21:32:11 -05:00
|
|
|
|
`()` Unit, the type that has only a single value
|
2012-09-22 23:14:58 -05:00
|
|
|
|
`bool` Boolean type, with values `true` and `false`
|
|
|
|
|
`int`, `uint` Machine-pointer-sized signed and unsigned integers
|
|
|
|
|
`i8`, `i16`, `i32`, `i64` Signed integers with a specific size (in bits)
|
|
|
|
|
`u8`, `u16`, `u32`, `u64` Unsigned integers with a specific size
|
|
|
|
|
`float` The largest floating-point type efficiently supported on the target machine
|
2012-10-04 19:33:06 -05:00
|
|
|
|
`f32`, `f64` Floating-point types with a specific size
|
|
|
|
|
`char` A Unicode character (32 bits)
|
2012-09-22 23:14:58 -05:00
|
|
|
|
------------------------- -----------------------------------------------
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
These can be combined in composite types, which will be described in
|
2012-10-03 19:52:04 -05:00
|
|
|
|
more detail later on (the `T`s here stand for any other type,
|
|
|
|
|
while N should be a literal number):
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 23:14:58 -05:00
|
|
|
|
------------------------- -----------------------------------------------
|
|
|
|
|
`[T * N]` Vector (like an array in other languages) with N elements
|
|
|
|
|
`[mut T * N]` Mutable vector with N elements
|
2012-10-04 19:33:06 -05:00
|
|
|
|
`(T1, T2)` Tuple type; any arity above 1 is supported
|
2012-09-26 19:54:01 -05:00
|
|
|
|
`&T`, `~T`, `@T` [Pointer types](#boxes-and-pointers)
|
2012-09-22 23:14:58 -05:00
|
|
|
|
------------------------- -----------------------------------------------
|
2012-08-31 18:57:37 -05:00
|
|
|
|
|
2012-08-31 19:20:36 -05:00
|
|
|
|
Some types can only be manipulated by pointer, never directly. For instance,
|
|
|
|
|
you cannot refer to a string (`str`); instead you refer to a pointer to a
|
|
|
|
|
string (`@str`, `~str`, or `&str`). These *dynamically-sized* types consist
|
|
|
|
|
of:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 23:14:58 -05:00
|
|
|
|
------------------------- -----------------------------------------------
|
|
|
|
|
`fn(a: T1, b: T2) -> T3` Function types
|
|
|
|
|
`str` String type (in UTF-8)
|
|
|
|
|
`[T]` Vector with unknown size (also called a slice)
|
|
|
|
|
`[mut T]` Mutable vector with unknown size
|
|
|
|
|
------------------------- -----------------------------------------------
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-11 22:13:04 -05:00
|
|
|
|
> ***Note***: In the future, mutability for vectors may be defined by
|
|
|
|
|
> the slot that contains the vector, not the type of the vector itself,
|
|
|
|
|
> deprecating [mut T] syntax.
|
|
|
|
|
|
2012-09-22 23:50:02 -05:00
|
|
|
|
In function types, the return type is specified with an arrow, as in
|
|
|
|
|
the type `fn() -> bool` or the function declaration `fn foo() -> bool
|
|
|
|
|
{ }`. For functions that do not return a meaningful value, you can
|
|
|
|
|
optionally write `-> ()`, but usually the return annotation is simply
|
|
|
|
|
left off, as in `fn main() { ... }`.
|
|
|
|
|
|
2012-10-03 19:52:04 -05:00
|
|
|
|
Types can be given names or aliases with `type` declarations:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-08-31 18:57:37 -05:00
|
|
|
|
type MonsterSize = uint;
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-08-31 18:57:37 -05:00
|
|
|
|
This will provide a synonym, `MonsterSize`, for unsigned integers. It will not
|
|
|
|
|
actually create a new, incompatible type—`MonsterSize` and `uint` can be used
|
|
|
|
|
interchangeably, and using one where the other is expected is not a type
|
2012-10-10 21:32:11 -05:00
|
|
|
|
error. In that sense, types declared with `type` are *structural*: their
|
|
|
|
|
meaning follows from their structure, and their names are irrelevant in the
|
|
|
|
|
type system.
|
2012-10-03 19:52:04 -05:00
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
Sometimes, you want your data types to be *nominal* instead of structural: you
|
|
|
|
|
want their name to be part of their meaning, so that types with the same
|
|
|
|
|
structure but different names are not interchangeable. Rust has two ways to
|
|
|
|
|
create nominal data types: `struct` and `enum`. They're described in more
|
|
|
|
|
detail below, but they look like this:
|
2012-10-03 19:52:04 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
enum HidingPlaces {
|
|
|
|
|
Closet(uint),
|
|
|
|
|
UnderTheBed(uint)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct HeroicBabysitter {
|
|
|
|
|
bedtime_stories: uint,
|
|
|
|
|
sharpened_stakes: uint
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct BabysitterSize(uint); // a single-variant struct
|
|
|
|
|
enum MonsterSize = uint; // a single-variant enum
|
|
|
|
|
~~~~
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-23 00:22:49 -05:00
|
|
|
|
## Literals
|
2012-06-20 19:09:30 -05:00
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
Integers can be written in decimal (`144`), hexadecimal (`0x90`), or
|
2012-09-23 00:22:49 -05:00
|
|
|
|
binary (`0b10010000`) base. Each integral type has a corresponding literal
|
|
|
|
|
suffix that can be used to indicate the type of a literal: `i` for `int`,
|
|
|
|
|
`u` for `uint`, and `i8` for the `i8` type, etc.
|
2012-06-20 19:09:30 -05:00
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
In the absence of an integer literal suffix, Rust will infer the
|
2012-09-23 00:22:49 -05:00
|
|
|
|
integer type based on type annotations and function signatures in the
|
|
|
|
|
surrounding program. In the absence of any type information at all,
|
|
|
|
|
Rust will assume that an unsuffixed integer literal has type
|
|
|
|
|
`int`.
|
2012-06-20 19:09:30 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-23 00:22:49 -05:00
|
|
|
|
let a = 1; // a is an int
|
|
|
|
|
let b = 10i; // b is an int, due to the 'i' suffix
|
2012-09-26 18:19:07 -05:00
|
|
|
|
let c = 100u; // c is a uint
|
2012-09-23 00:22:49 -05:00
|
|
|
|
let d = 1000i32; // d is an i32
|
2012-06-20 19:09:30 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
Floating point numbers are written `0.0`, `1e6`, or `2.1e-4`. Without
|
2012-09-23 00:22:49 -05:00
|
|
|
|
a suffix, the literal is assumed to be of type `float`. Suffixes `f32`
|
|
|
|
|
(32-bit) and `f64` (64-bit) can be used to create literals of a
|
|
|
|
|
specific type.
|
2012-06-20 19:09:30 -05:00
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
The unit literal is written just like the type: `()`. The keywords
|
2012-01-19 05:51:20 -06:00
|
|
|
|
`true` and `false` produce the boolean literals.
|
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
Character literals are written between single quotes, as in `'x'`. Just like
|
2012-08-31 18:57:37 -05:00
|
|
|
|
C, Rust understands a number of character escapes, using the backslash
|
2012-10-03 19:52:04 -05:00
|
|
|
|
character, such as `\n`, `\r`, and `\t`. String literals,
|
2012-09-23 01:11:24 -05:00
|
|
|
|
written between double quotes, allow the same escape sequences. Rust strings
|
|
|
|
|
may contain newlines.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-04 21:36:56 -05:00
|
|
|
|
## Constants
|
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
Compile-time constants are declared with `const`. A constant may have any
|
|
|
|
|
scalar type (for example, integer or float). Other allowable constant types
|
|
|
|
|
are fixed-length vectors, static strings (more on this later), and
|
|
|
|
|
structs. Constants may be declared in any scope and may refer to other
|
|
|
|
|
constants. The compiler does not infer types for constants, so constants must
|
|
|
|
|
always be declared with a type annotation. By convention, they are written in
|
|
|
|
|
all capital letters.
|
2012-10-04 21:36:56 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
// Scalars can be constants
|
|
|
|
|
const MY_PASSWORD: int = 12345;
|
|
|
|
|
|
|
|
|
|
// Scalar constants can be combined with other constants
|
|
|
|
|
const MY_DOGGIES_PASSWORD: int = MY_PASSWORD + 1;
|
|
|
|
|
|
|
|
|
|
// Fixed-length vectors
|
|
|
|
|
const MY_VECTORY_PASSWORD: [int * 5] = [1, 2, 3, 4, 5];
|
|
|
|
|
|
|
|
|
|
// Static strings
|
|
|
|
|
const MY_STRINGY_PASSWORD: &static/str = "12345";
|
|
|
|
|
|
|
|
|
|
// Structs
|
2012-10-04 21:47:09 -05:00
|
|
|
|
struct Password { value: int }
|
2012-10-04 21:36:56 -05:00
|
|
|
|
const MY_STRUCTY_PASSWORD: Password = Password { value: MY_PASSWORD };
|
|
|
|
|
~~~
|
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
## Operators
|
|
|
|
|
|
2012-08-31 19:20:36 -05:00
|
|
|
|
Rust's set of operators contains very few surprises. Arithmetic is done with
|
2012-11-11 10:19:40 -06:00
|
|
|
|
`*`, `/`, `%`, `+`, and `-` (multiply, divide, take remainder, add, subtract). `-` is
|
2012-10-10 21:32:11 -05:00
|
|
|
|
also a unary prefix operator that negates numbers. As in C, the bit operators
|
2012-08-31 19:20:36 -05:00
|
|
|
|
`>>`, `<<`, `&`, `|`, and `^` are also supported.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-08-31 19:20:36 -05:00
|
|
|
|
Note that, if applied to an integer value, `!` flips all the bits (like `~` in
|
|
|
|
|
C).
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
The comparison operators are the traditional `==`, `!=`, `<`, `>`,
|
|
|
|
|
`<=`, and `>=`. Short-circuiting (lazy) boolean operators are written
|
|
|
|
|
`&&` (and) and `||` (or).
|
|
|
|
|
|
2012-08-31 19:20:36 -05:00
|
|
|
|
For type casting, Rust uses the binary `as` operator. It takes an
|
|
|
|
|
expression on the left side and a type on the right side and will,
|
2012-05-16 22:22:32 -05:00
|
|
|
|
if a meaningful conversion exists, convert the result of the
|
|
|
|
|
expression to the given type.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
let x: float = 4.0;
|
|
|
|
|
let y: uint = x as uint;
|
|
|
|
|
assert y == 4u;
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-07-02 18:27:53 -05:00
|
|
|
|
The main difference with C is that `++` and `--` are missing, and that
|
2012-10-10 21:32:11 -05:00
|
|
|
|
the logical bitwise operators have higher precedence—in C, `x & 2 > 0`
|
2012-10-03 19:52:04 -05:00
|
|
|
|
means `x & (2 > 0)`, but in Rust, it means `(x & 2) > 0`, which is
|
2012-10-10 21:32:11 -05:00
|
|
|
|
more likely to be what a novice expects.
|
2012-07-02 18:27:53 -05:00
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
## Syntax extensions
|
|
|
|
|
|
2012-08-31 19:20:36 -05:00
|
|
|
|
*Syntax extensions* are special forms that are not built into the language,
|
|
|
|
|
but are instead provided by the libraries. To make it clear to the reader when
|
2012-10-10 21:32:11 -05:00
|
|
|
|
a name refers to a syntax extension, the names of all syntax extensions end
|
|
|
|
|
with `!`. The standard library defines a few syntax extensions, the most
|
|
|
|
|
useful of which is `fmt!`, a `sprintf`-style text formatter that an early
|
|
|
|
|
compiler phase expands statically.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
`fmt!` supports most of the directives that [printf][pf] supports, but unlike
|
|
|
|
|
printf, will give you a compile-time error when the types of the directives
|
2012-01-19 05:51:20 -06:00
|
|
|
|
don't match the types of the arguments.
|
|
|
|
|
|
2012-09-23 01:11:24 -05:00
|
|
|
|
~~~~
|
|
|
|
|
# let mystery_object = ();
|
|
|
|
|
|
2012-10-03 22:03:37 -05:00
|
|
|
|
io::println(fmt!("%s is %d", "the answer", 43));
|
2012-09-23 01:11:24 -05:00
|
|
|
|
|
|
|
|
|
// %? will conveniently print any type
|
|
|
|
|
io::println(fmt!("what is this thing: %?", mystery_object));
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
[pf]: http://en.cppreference.com/w/cpp/io/c/fprintf
|
|
|
|
|
|
2012-10-10 21:32:11 -05:00
|
|
|
|
You can define your own syntax extensions with the macro system. For details, see the [macro tutorial][macros].
|
|
|
|
|
|
|
|
|
|
[macros]: tutorial-macros.html
|
2012-08-22 21:07:46 -05:00
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
# Control structures
|
|
|
|
|
|
|
|
|
|
## Conditionals
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
We've seen `if` expressions a few times already. To recap, braces are
|
|
|
|
|
compulsory, an `if` can have an optional `else` clause, and multiple
|
2012-01-19 05:51:20 -06:00
|
|
|
|
`if`/`else` constructs can be chained together:
|
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
if false {
|
2012-09-23 01:11:24 -05:00
|
|
|
|
io::println("that's odd");
|
2012-01-19 05:51:20 -06:00
|
|
|
|
} else if true {
|
2012-09-23 01:11:24 -05:00
|
|
|
|
io::println("right");
|
2012-01-19 05:51:20 -06:00
|
|
|
|
} else {
|
2012-09-23 01:11:24 -05:00
|
|
|
|
io::println("neither true nor false");
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
The condition given to an `if` construct *must* be of type `bool` (no
|
|
|
|
|
implicit conversion happens). If the arms are blocks that have a
|
|
|
|
|
value, this value must be of the same type for every arm in which
|
|
|
|
|
control reaches the end of the block:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
fn signum(x: int) -> int {
|
|
|
|
|
if x < 0 { -1 }
|
|
|
|
|
else if x > 0 { 1 }
|
2012-08-31 18:57:37 -05:00
|
|
|
|
else { return 0 }
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
## Pattern matching
|
|
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
|
Rust's `match` construct is a generalized, cleaned-up version of C's
|
2012-10-10 22:08:08 -05:00
|
|
|
|
`switch` construct. You provide it with a value and a number of
|
|
|
|
|
*arms*, each labelled with a pattern, and the code compares the value
|
|
|
|
|
against each pattern in order until one matches. The matching pattern
|
|
|
|
|
executes its corresponding arm.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
# let my_number = 1;
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match my_number {
|
2012-08-31 18:57:37 -05:00
|
|
|
|
0 => io::println("zero"),
|
|
|
|
|
1 | 2 => io::println("one or two"),
|
|
|
|
|
3..10 => io::println("three to ten"),
|
|
|
|
|
_ => io::println("something else")
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
Unlike in C, there is no 'falling through' between arms: only one arm
|
|
|
|
|
executes, and it doesn't have to explicitly `break` out of the
|
2012-01-19 05:51:20 -06:00
|
|
|
|
construct when it is finished.
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
A `match` arm consists of a *pattern*, then an arrow `=>`, followed by
|
|
|
|
|
an *action* (expression). Literals are valid patterns and match only
|
|
|
|
|
their own value. A single arm may match multiple different patterns by
|
|
|
|
|
combining them with the pipe operator (`|`), so long as every pattern
|
|
|
|
|
binds the same set of variables. Ranges of numeric literal patterns
|
|
|
|
|
can be expressed with two dots, as in `M..N`. The underscore (`_`) is
|
|
|
|
|
a wildcard pattern that matches any single value. The asterisk (`*`)
|
|
|
|
|
is a different wildcard that can match one or more fields in an `enum`
|
|
|
|
|
variant.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-11-11 10:19:40 -06:00
|
|
|
|
The patterns in a match arm are followed by a fat arrow, `=>`, then an
|
2012-08-06 00:07:22 -05:00
|
|
|
|
expression to evaluate. Each case is separated by commas. It's often
|
2012-10-03 19:52:04 -05:00
|
|
|
|
convenient to use a block expression for each case, in which case the
|
2012-08-06 00:07:22 -05:00
|
|
|
|
commas are optional.
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
# let my_number = 1;
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match my_number {
|
2012-10-03 19:52:04 -05:00
|
|
|
|
0 => { io::println("zero") }
|
|
|
|
|
_ => { io::println("something else") }
|
2012-08-06 00:07:22 -05:00
|
|
|
|
}
|
|
|
|
|
~~~
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
`match` constructs must be *exhaustive*: they must have an arm
|
|
|
|
|
covering every possible case. For example, the typechecker would
|
|
|
|
|
reject the previous example if the arm with the wildcard pattern was
|
|
|
|
|
omitted.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
A powerful application of pattern matching is *destructuring*:
|
|
|
|
|
matching in order to bind names to the contents of data
|
|
|
|
|
types. Remember that `(float, float)` is a tuple of two floats:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-08-31 18:57:37 -05:00
|
|
|
|
fn angle(vector: (float, float)) -> float {
|
2012-09-24 21:51:03 -05:00
|
|
|
|
let pi = float::consts::pi;
|
2012-08-31 18:57:37 -05:00
|
|
|
|
match vector {
|
|
|
|
|
(0f, y) if y < 0f => 1.5 * pi,
|
|
|
|
|
(0f, y) => 0.5 * pi,
|
2012-08-06 00:07:22 -05:00
|
|
|
|
(x, y) => float::atan(y / x)
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
A variable name in a pattern matches any value, *and* binds that name
|
|
|
|
|
to the value of the matched value inside of the arm's action. Thus, `(0f,
|
2012-01-19 05:51:20 -06:00
|
|
|
|
y)` matches any tuple whose first element is zero, and binds `y` to
|
|
|
|
|
the second element. `(x, y)` matches any tuple, and binds both
|
2012-10-10 22:08:08 -05:00
|
|
|
|
elements to variables.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
Any `match` arm can have a guard clause (written `if EXPR`), called a
|
|
|
|
|
*pattern guard*, which is an expression of type `bool` that
|
|
|
|
|
determines, after the pattern is found to match, whether the arm is
|
|
|
|
|
taken or not. The variables bound by the pattern are in scope in this
|
|
|
|
|
guard expression. The first arm in the `angle` example shows an
|
|
|
|
|
example of a pattern guard.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-24 21:51:03 -05:00
|
|
|
|
You've already seen simple `let` bindings, but `let` is a little
|
2012-10-10 22:08:08 -05:00
|
|
|
|
fancier than you've been led to believe. It, too, supports destructuring
|
|
|
|
|
patterns. For example, you can write this to extract the fields from a
|
|
|
|
|
tuple, introducing two variables at once: `a` and `b`.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
# fn get_tuple_of_two_ints() -> (int, int) { (1, 1) }
|
|
|
|
|
let (a, b) = get_tuple_of_two_ints();
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
Let bindings only work with _irrefutable_ patterns: that is, patterns
|
2012-09-24 21:51:03 -05:00
|
|
|
|
that can never fail to match. This excludes `let` from matching
|
2012-10-10 22:08:08 -05:00
|
|
|
|
literals and most `enum` variants.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
## Loops
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
`while` denotes a loop that iterates as long as its given condition
|
|
|
|
|
(which must have type `bool`) evaluates to `true`. Inside a loop, the
|
|
|
|
|
keyword `break` aborts the loop, and `loop` aborts the current
|
|
|
|
|
iteration and continues with the next.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-05-10 16:06:19 -05:00
|
|
|
|
~~~~
|
|
|
|
|
let mut cake_amount = 8;
|
|
|
|
|
while cake_amount > 0 {
|
|
|
|
|
cake_amount -= 1;
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
`loop` denotes an infinite loop, and is the preferred way of writing `while true`:
|
2012-05-10 16:06:19 -05:00
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
2012-03-22 10:39:41 -05:00
|
|
|
|
let mut x = 5;
|
2012-07-01 21:20:43 -05:00
|
|
|
|
loop {
|
2012-01-19 05:51:20 -06:00
|
|
|
|
x += x - 3;
|
|
|
|
|
if x % 5 == 0 { break; }
|
2012-03-12 22:04:27 -05:00
|
|
|
|
io::println(int::str(x));
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
This code prints out a weird sequence of numbers and stops as soon as
|
|
|
|
|
it finds one that can be divided by five.
|
|
|
|
|
|
2012-10-10 22:08:08 -05:00
|
|
|
|
For more involved iteration, such as enumerating the elements of a
|
|
|
|
|
collection, Rust uses [higher-order functions](#closures).
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:45:48 -05:00
|
|
|
|
# Data structures
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-08-31 18:57:37 -05:00
|
|
|
|
## Structs
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-08-31 18:57:37 -05:00
|
|
|
|
Rust struct types must be declared before they are used using the `struct`
|
|
|
|
|
syntax: `struct Name { field1: T1, field2: T2 [, ...] }`, where `T1`, `T2`,
|
|
|
|
|
... denote types. To construct a struct, use the same syntax, but leave off
|
2012-10-10 22:35:33 -05:00
|
|
|
|
the `struct`: for example: `Point { x: 1.0, y: 2.0 }`.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-08-31 18:57:37 -05:00
|
|
|
|
Structs are quite similar to C structs and are even laid out the same way in
|
2012-10-10 22:35:33 -05:00
|
|
|
|
memory (so you can read from a Rust struct in C, and vice-versa). Use the dot
|
|
|
|
|
operator to access struct fields, as in `mypoint.x`.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-08-31 18:57:37 -05:00
|
|
|
|
Fields that you want to mutate must be explicitly marked `mut`.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-08-31 18:57:37 -05:00
|
|
|
|
struct Stack {
|
|
|
|
|
content: ~[int],
|
|
|
|
|
mut head: uint
|
|
|
|
|
}
|
2012-07-07 18:23:10 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-08-31 18:57:37 -05:00
|
|
|
|
With a value of such a type, you can do `mystack.head += 1`. If `mut` were
|
|
|
|
|
omitted from the type, such an assignment would result in a type error.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
`match` patterns destructure structs. The basic syntax is
|
2012-08-31 18:57:37 -05:00
|
|
|
|
`Name {fieldname: pattern, ...}`:
|
2012-10-04 22:03:40 -05:00
|
|
|
|
|
2012-07-07 18:23:10 -05:00
|
|
|
|
~~~~
|
2012-08-31 18:57:37 -05:00
|
|
|
|
# struct Point { x: float, y: float }
|
|
|
|
|
# let mypoint = Point { x: 0.0, y: 0.0 };
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match mypoint {
|
2012-10-04 14:41:45 -05:00
|
|
|
|
Point { x: 0.0, y: yy } => { io::println(yy.to_str()); }
|
|
|
|
|
Point { x: xx, y: yy } => { io::println(xx.to_str() + " " + yy.to_str()); }
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-08-31 18:57:37 -05:00
|
|
|
|
In general, the field names of a struct do not have to appear in the same
|
|
|
|
|
order they appear in the type. When you are not interested in all
|
|
|
|
|
the fields of a struct, a struct pattern may end with `, _` (as in
|
|
|
|
|
`Name {field1, _}`) to indicate that you're ignoring all other fields.
|
2012-10-04 22:03:40 -05:00
|
|
|
|
Additionally, struct fields have a shorthand matching form that simply
|
|
|
|
|
reuses the field name as the binding name.
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
# struct Point { x: float, y: float }
|
|
|
|
|
# let mypoint = Point { x: 0.0, y: 0.0 };
|
|
|
|
|
match mypoint {
|
|
|
|
|
Point { x, _ } => { io::println(x.to_str()) }
|
|
|
|
|
}
|
|
|
|
|
~~~
|
|
|
|
|
|
2012-07-07 18:23:10 -05:00
|
|
|
|
## Enums
|
|
|
|
|
|
|
|
|
|
Enums are datatypes that have several alternate representations. For
|
|
|
|
|
example, consider the type shown earlier:
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-08-31 18:57:37 -05:00
|
|
|
|
# struct Point { x: float, y: float }
|
|
|
|
|
enum Shape {
|
|
|
|
|
Circle(Point, float),
|
|
|
|
|
Rectangle(Point, Point)
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-09-26 18:41:14 -05:00
|
|
|
|
A value of this type is either a `Circle`, in which case it contains a
|
|
|
|
|
`Point` struct and a float, or a `Rectangle`, in which case it contains
|
|
|
|
|
two `Point` structs. The run-time representation of such a value
|
2012-07-07 18:23:10 -05:00
|
|
|
|
includes an identifier of the actual form that it holds, much like the
|
2012-10-10 22:35:33 -05:00
|
|
|
|
'tagged union' pattern in C, but with better static guarantees.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
The above declaration will define a type `Shape` that can refer to
|
|
|
|
|
such shapes, and two functions, `Circle` and `Rectangle`, which can be
|
|
|
|
|
used to construct values of the type (taking arguments of the
|
|
|
|
|
specified types). So `Circle(Point {x: 0f, y: 0f}, 10f)` is the way to
|
2012-07-07 18:23:10 -05:00
|
|
|
|
create a new circle.
|
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
Enum variants need not have type parameters. This `enum` declaration,
|
|
|
|
|
for example, is equivalent to a C enum:
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
enum Direction {
|
|
|
|
|
North,
|
|
|
|
|
East,
|
|
|
|
|
South,
|
|
|
|
|
West
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
This declaration defines `North`, `East`, `South`, and `West` as constants,
|
2012-09-15 20:44:44 -05:00
|
|
|
|
all of which have type `Direction`.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
When an enum is C-like (that is, when none of the variants have
|
|
|
|
|
parameters), it is possible to explicitly set the discriminator values
|
|
|
|
|
to a constant value:
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
enum Color {
|
|
|
|
|
Red = 0xff0000,
|
|
|
|
|
Green = 0x00ff00,
|
|
|
|
|
Blue = 0x0000ff
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
If an explicit discriminator is not specified for a variant, the value
|
|
|
|
|
defaults to the value of the previous variant plus one. If the first
|
|
|
|
|
variant does not have a discriminator, it defaults to 0. For example,
|
2012-10-10 22:35:33 -05:00
|
|
|
|
the value of `North` is 0, `East` is 1, `South` is 2, and `West` is 3.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
When an enum is C-like, you can apply the `as` cast operator to
|
|
|
|
|
convert it to its discriminator value as an int.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
<a name="single_variant_enum"></a>
|
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
There is a special case for enums with a single variant, which are
|
|
|
|
|
sometimes called "newtype-style enums" (after Haskell's "newtype"
|
|
|
|
|
feature). These are used to define new types in such a way that the
|
|
|
|
|
new name is not just a synonym for an existing type, but its own
|
|
|
|
|
distinct type: `type` creates a structural synonym, while this form of
|
|
|
|
|
`enum` creates a nominal synonym. If you say:
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
enum GizmoId = int;
|
2012-07-07 18:23:10 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
That is a shorthand for this:
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
enum GizmoId { GizmoId(int) }
|
2012-07-07 18:23:10 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
You can extract the contents of such an enum type with the
|
2012-07-07 18:23:10 -05:00
|
|
|
|
dereference (`*`) unary operator:
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# enum GizmoId = int;
|
2012-10-04 14:41:45 -05:00
|
|
|
|
let my_gizmo_id: GizmoId = GizmoId(10);
|
2012-07-07 18:23:10 -05:00
|
|
|
|
let id_int: int = *my_gizmo_id;
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
Types like this can be useful to differentiate between data that have
|
|
|
|
|
the same type but must be used in different ways.
|
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
enum Inches = int;
|
|
|
|
|
enum Centimeters = int;
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
The above definitions allow for a simple way for programs to avoid
|
|
|
|
|
confusing numbers that correspond to different units.
|
|
|
|
|
|
2012-07-07 18:23:10 -05:00
|
|
|
|
For enum types with multiple variants, destructuring is the only way to
|
|
|
|
|
get at their contents. All variant constructors can be used as
|
|
|
|
|
patterns, as in this definition of `area`:
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-10-07 00:35:08 -05:00
|
|
|
|
# struct Point {x: float, y: float}
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# enum Shape { Circle(Point, float), Rectangle(Point, Point) }
|
|
|
|
|
fn area(sh: Shape) -> float {
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match sh {
|
2012-09-15 20:44:44 -05:00
|
|
|
|
Circle(_, size) => float::consts::pi * size * size,
|
2012-10-07 00:35:08 -05:00
|
|
|
|
Rectangle(Point {x, y}, Point {x: x2, y: y2}) => (x2 - x) * (y2 - y)
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-11-11 10:19:40 -06:00
|
|
|
|
You can write a lone `_` to ignore an individual field, and can
|
2012-10-10 22:35:33 -05:00
|
|
|
|
ignore all fields of a variant like: `Circle(*)`. As in their
|
|
|
|
|
introduction form, nullary enum patterns are written without
|
2012-09-23 20:02:28 -05:00
|
|
|
|
parentheses.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-10-07 00:35:08 -05:00
|
|
|
|
# struct Point {x: float, y: float}
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# enum Direction { North, East, South, West }
|
|
|
|
|
fn point_from_direction(dir: Direction) -> Point {
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match dir {
|
2012-10-06 03:56:29 -05:00
|
|
|
|
North => Point {x: 0f, y: 1f},
|
|
|
|
|
East => Point {x: 1f, y: 0f},
|
|
|
|
|
South => Point {x: 0f, y: -1f},
|
|
|
|
|
West => Point {x: -1f, y: 0f}
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
## Tuples
|
|
|
|
|
|
2012-09-26 18:41:14 -05:00
|
|
|
|
Tuples in Rust behave exactly like structs, except that their fields
|
2012-10-10 22:35:33 -05:00
|
|
|
|
do not have names. Thus, you cannot access their fields with dot notation.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
Tuples can have any arity except for 0 or 1 (though you may consider
|
2012-10-10 22:35:33 -05:00
|
|
|
|
unit, `()`, as the empty tuple if you like).
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
let mytup: (int, int, float) = (10, 20, 30.0);
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match mytup {
|
2012-08-06 00:07:22 -05:00
|
|
|
|
(a, b, c) => log(info, a + b + (c as int))
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
2012-07-07 17:37:58 -05:00
|
|
|
|
|
2012-09-24 20:25:57 -05:00
|
|
|
|
# Functions and methods
|
|
|
|
|
|
|
|
|
|
We've already seen several function definitions. Like all other static
|
|
|
|
|
declarations, such as `type`, functions can be declared both at the
|
2012-10-10 22:35:33 -05:00
|
|
|
|
top level and inside other functions (or in modules, which we'll come
|
|
|
|
|
back to [later](#modules-and-crates)). The `fn` keyword introduces a
|
|
|
|
|
function. A function has an argument list, which is a parenthesized
|
|
|
|
|
list of `expr: type` pairs separated by commas. An arrow `->`
|
|
|
|
|
separates the argument list and the function's return type.
|
2012-09-24 20:25:57 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-10-04 14:41:45 -05:00
|
|
|
|
fn line(a: int, b: int, x: int) -> int {
|
2012-10-04 19:33:06 -05:00
|
|
|
|
return a * x + b;
|
2012-09-24 20:25:57 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
The `return` keyword immediately returns from the body of a function. It
|
|
|
|
|
is optionally followed by an expression to return. A function can
|
|
|
|
|
also return a value by having its top level block produce an
|
|
|
|
|
expression.
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-10-04 14:41:45 -05:00
|
|
|
|
fn line(a: int, b: int, x: int) -> int {
|
2012-10-04 19:33:06 -05:00
|
|
|
|
a * x + b
|
2012-09-24 20:25:57 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
It's better Rust style to write a return value this way instead of
|
|
|
|
|
writing an explicit `return`. The utility of `return` comes in when
|
|
|
|
|
returning early from a function. Functions that do not return a value
|
|
|
|
|
are said to return nil, `()`, and both the return type and the return
|
|
|
|
|
value may be omitted from the definition. The following two functions
|
|
|
|
|
are equivalent.
|
2012-09-24 20:25:57 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
fn do_nothing_the_hard_way() -> () { return (); }
|
|
|
|
|
|
|
|
|
|
fn do_nothing_the_easy_way() { }
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-04 14:41:45 -05:00
|
|
|
|
Ending the function with a semicolon like so is equivalent to returning `()`.
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-10-04 19:33:06 -05:00
|
|
|
|
fn line(a: int, b: int, x: int) -> int { a * x + b }
|
|
|
|
|
fn oops(a: int, b: int, x: int) -> () { a * x + b; }
|
2012-10-04 14:41:45 -05:00
|
|
|
|
|
2012-10-04 19:33:06 -05:00
|
|
|
|
assert 8 == line(5, 3, 1);
|
|
|
|
|
assert () == oops(5, 3, 1);
|
2012-10-04 14:41:45 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
Methods are like functions, except that they have an implicit argument
|
|
|
|
|
called `self`, which has the type that the method's receiver has. The
|
|
|
|
|
`self` argument is like 'this' in C++. An expression with dot
|
|
|
|
|
notation, as in `my_vec.len()`, denotes a method
|
|
|
|
|
call. Implementations, written with the `impl` keyword, can define
|
|
|
|
|
methods on most Rust types. As an example, let's define a `draw`
|
2012-09-24 20:25:57 -05:00
|
|
|
|
method on our `Shape` enum.
|
|
|
|
|
|
|
|
|
|
~~~
|
2012-09-24 21:11:48 -05:00
|
|
|
|
# fn draw_circle(p: Point, f: float) { }
|
|
|
|
|
# fn draw_rectangle(p: Point, p: Point) { }
|
2012-09-24 20:25:57 -05:00
|
|
|
|
struct Point {
|
|
|
|
|
x: float,
|
|
|
|
|
y: float
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum Shape {
|
|
|
|
|
Circle(Point, float),
|
|
|
|
|
Rectangle(Point, Point)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Shape {
|
|
|
|
|
fn draw() {
|
|
|
|
|
match self {
|
|
|
|
|
Circle(p, f) => draw_circle(p, f),
|
|
|
|
|
Rectangle(p1, p2) => draw_rectangle(p1, p2)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-24 21:11:48 -05:00
|
|
|
|
let s = Circle(Point { x: 1f, y: 2f }, 3f);
|
2012-09-24 20:25:57 -05:00
|
|
|
|
s.draw();
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
|
|
This defines an _implementation_ for `Shape` containing a single
|
2012-10-08 19:24:54 -05:00
|
|
|
|
method, `draw`. In most respects the `draw` method is defined
|
2012-10-10 22:35:33 -05:00
|
|
|
|
like any other function, except for the name `self`. `self`
|
|
|
|
|
is a special value that is automatically in scope inside each method,
|
2012-09-24 21:11:48 -05:00
|
|
|
|
referring to the value being operated on. If we wanted we could add
|
|
|
|
|
additional methods to the same impl, or multiple impls for the same
|
|
|
|
|
type. We'll discuss methods more in the context of [traits and
|
|
|
|
|
generics](#generics).
|
2012-09-24 20:25:57 -05:00
|
|
|
|
|
2012-10-10 22:35:33 -05:00
|
|
|
|
> ***Note:*** In the future, the method definition syntax will change to
|
|
|
|
|
> require declaring the `self` type explicitly, as the first argument.
|
2012-09-24 20:25:57 -05:00
|
|
|
|
|
2012-07-08 02:04:49 -05:00
|
|
|
|
# The Rust memory model
|
2012-07-06 16:34:41 -05:00
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
At this junction, let's take a detour to explain the concepts involved
|
2012-09-24 20:25:57 -05:00
|
|
|
|
in Rust's memory model. We've seen some of Rust's pointer sigils (`@`,
|
|
|
|
|
`~`, and `&`) float by in a few examples, and we aren't going to get
|
|
|
|
|
much further without explaining them. Rust has a very particular
|
|
|
|
|
approach to memory management that plays a significant role in shaping
|
2012-10-10 22:52:20 -05:00
|
|
|
|
the subjective experience of programming in the
|
|
|
|
|
language. Understanding the memory landscape will illuminate several
|
|
|
|
|
of Rust's unique features as we encounter them.
|
2012-07-06 16:34:41 -05:00
|
|
|
|
|
|
|
|
|
Rust has three competing goals that inform its view of memory:
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
* Memory safety: Memory that the Rust language can observe must be
|
|
|
|
|
guaranteed to be valid. Under normal circumstances, it must be
|
|
|
|
|
impossible for Rust to trigger a segmentation fault or leak memory.
|
|
|
|
|
* Performance: High-performance low-level code must be able to use
|
|
|
|
|
a number of different allocation strategies. Tracing garbage collection must be
|
2012-10-09 23:39:18 -05:00
|
|
|
|
optional and, if it is not desired, memory safety must not be compromised.
|
|
|
|
|
Less performance-critical, high-level code should be able to employ a single,
|
|
|
|
|
garbage-collection-based, heap allocation strategy.
|
|
|
|
|
* Concurrency: Rust code must be free of in-memory data races. (Note that other
|
|
|
|
|
types of races are still possible.)
|
2012-07-06 16:34:41 -05:00
|
|
|
|
|
|
|
|
|
## How performance considerations influence the memory model
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
Most languages that offer strong memory safety guarantees rely on a
|
2012-07-22 21:19:30 -05:00
|
|
|
|
garbage-collected heap to manage all of the objects. This approach is
|
|
|
|
|
straightforward both in concept and in implementation, but has
|
2012-09-26 20:54:36 -05:00
|
|
|
|
significant costs. Languages that follow this path tend to
|
2012-07-22 21:19:30 -05:00
|
|
|
|
aggressively pursue ways to ameliorate allocation costs (think the
|
2012-09-23 20:45:42 -05:00
|
|
|
|
Java Virtual Machine). Rust supports this strategy with _managed
|
|
|
|
|
boxes_: memory allocated on the heap whose lifetime is managed
|
|
|
|
|
by the garbage collector.
|
2012-07-22 21:12:51 -05:00
|
|
|
|
|
|
|
|
|
By comparison, languages like C++ offer very precise control over
|
2012-10-10 22:52:20 -05:00
|
|
|
|
where objects are allocated. In particular, it is common to allocate them
|
2012-07-22 21:12:51 -05:00
|
|
|
|
directly on the stack, avoiding expensive heap allocation. In Rust
|
2012-10-10 22:52:20 -05:00
|
|
|
|
this is possible as well, and the compiler uses a [clever _pointer
|
|
|
|
|
lifetime analysis_][borrow] to ensure that no variable can refer to stack
|
2012-07-06 16:34:41 -05:00
|
|
|
|
objects after they are destroyed.
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
[borrow]: tutorial-borrowed-ptr.html
|
|
|
|
|
|
2012-07-06 16:34:41 -05:00
|
|
|
|
## How concurrency considerations influence the memory model
|
|
|
|
|
|
2012-07-22 21:12:51 -05:00
|
|
|
|
Memory safety in a concurrent environment involves avoiding race
|
2012-07-06 16:34:41 -05:00
|
|
|
|
conditions between two threads of execution accessing the same
|
2012-10-10 22:52:20 -05:00
|
|
|
|
memory. Even high-level languages often require programmers to make
|
|
|
|
|
correct use of locking to ensure that a program is free of races.
|
2012-07-22 21:12:51 -05:00
|
|
|
|
|
|
|
|
|
Rust starts from the position that memory cannot be shared between
|
|
|
|
|
tasks. Experience in other languages has proven that isolating each
|
|
|
|
|
task's heap from the others is a reliable strategy and one that is
|
|
|
|
|
easy for programmers to reason about. Heap isolation has the
|
|
|
|
|
additional benefit that garbage collection must only be done
|
2012-09-26 20:54:36 -05:00
|
|
|
|
per-heap. Rust never "stops the world" to reclaim memory.
|
2012-07-22 21:12:51 -05:00
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
Complete isolation of heaps between tasks would, however, mean that
|
|
|
|
|
any data transferred between tasks must be copied. While this is a
|
|
|
|
|
fine and useful way to implement communication between tasks, it is
|
|
|
|
|
also very inefficient for large data structures. To reduce the amount
|
|
|
|
|
of copying, Rust also uses a global _exchange heap_. Objects allocated
|
|
|
|
|
in the exchange heap have _ownership semantics_, meaning that there is
|
|
|
|
|
only a single variable that refers to them. For this reason, they are
|
|
|
|
|
referred to as _owned boxes_. All tasks may allocate objects on the
|
|
|
|
|
exchange heap, then transfer ownership of those objects to other
|
|
|
|
|
tasks, avoiding expensive copies.
|
2012-07-06 16:34:41 -05:00
|
|
|
|
|
2012-07-07 18:49:51 -05:00
|
|
|
|
# Boxes and pointers
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
Many modern languages have a so-called "uniform representation" for
|
|
|
|
|
aggregate types like structs and enums, so as to represent these types
|
|
|
|
|
as pointers to heap memory by default. In contrast, Rust, like C and
|
|
|
|
|
C++, represents such types directly. Another way to say this is that
|
|
|
|
|
aggregate data in Rust are *unboxed*. This means that if you `let x =
|
|
|
|
|
Point {x: 1f, y: 1f};`, you are creating a struct on the stack. If you
|
|
|
|
|
then copy it into a data structure, you copy the entire struct, not
|
|
|
|
|
just a pointer.
|
2012-07-01 21:20:43 -05:00
|
|
|
|
|
2012-09-26 18:41:14 -05:00
|
|
|
|
For small structs like `Point`, this is usually more efficient than
|
2012-10-10 22:52:20 -05:00
|
|
|
|
allocating memory and indirecting through a pointer. But for big structs, or
|
2012-09-26 18:41:14 -05:00
|
|
|
|
those with mutable fields, it can be useful to have a single copy on
|
2012-10-09 23:21:07 -05:00
|
|
|
|
the stack or on the heap, and refer to that through a pointer.
|
2012-07-01 21:20:43 -05:00
|
|
|
|
|
2012-07-07 18:23:10 -05:00
|
|
|
|
Rust supports several types of pointers. The safe pointer types are
|
2012-09-23 20:45:42 -05:00
|
|
|
|
`@T` for managed boxes allocated on the local heap, `~T`, for
|
2012-07-07 18:23:10 -05:00
|
|
|
|
uniquely-owned boxes allocated on the exchange heap, and `&T`, for
|
|
|
|
|
borrowed pointers, which may point to any memory, and whose lifetimes
|
|
|
|
|
are governed by the call stack.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-07-07 18:23:10 -05:00
|
|
|
|
All pointer types can be dereferenced with the `*` unary operator.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
> ***Note***: You may also hear managed boxes referred to as 'shared
|
|
|
|
|
> boxes' or 'shared pointers', and owned boxes as 'unique boxes/pointers'.
|
|
|
|
|
> Borrowed pointers are sometimes called 'region pointers'. The preferred
|
2012-10-10 22:52:20 -05:00
|
|
|
|
> terminology is what we present here.
|
2012-07-01 21:20:43 -05:00
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
## Managed boxes
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
Managed boxes are pointers to heap-allocated, garbage collected
|
|
|
|
|
memory. Applying the unary `@` operator to an expression creates a
|
|
|
|
|
managed box. The resulting box contains the result of the
|
2012-11-11 10:19:40 -06:00
|
|
|
|
expression. Copying a managed box, as happens during assignment, only
|
2012-10-10 22:52:20 -05:00
|
|
|
|
copies a pointer, never the contents of the box.
|
2012-07-01 21:20:43 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-24 21:11:48 -05:00
|
|
|
|
let x: @int = @10; // New box
|
|
|
|
|
let y = x; // Copy of a pointer to the same box
|
|
|
|
|
|
|
|
|
|
// x and y both refer to the same allocation. When both go out of scope
|
|
|
|
|
// then the allocation will be freed.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
A _managed_ type is either of the form `@T` for some type `T`, or any
|
|
|
|
|
type that contains managed boxes or other managed types.
|
2012-09-24 21:37:41 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
// A linked list node
|
|
|
|
|
struct Node {
|
|
|
|
|
mut next: MaybeNode,
|
|
|
|
|
mut prev: MaybeNode,
|
|
|
|
|
payload: int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum MaybeNode {
|
|
|
|
|
SomeNode(@Node),
|
|
|
|
|
NoNode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let node1 = @Node { next: NoNode, prev: NoNode, payload: 1 };
|
|
|
|
|
let node2 = @Node { next: NoNode, prev: NoNode, payload: 2 };
|
|
|
|
|
let node3 = @Node { next: NoNode, prev: NoNode, payload: 3 };
|
|
|
|
|
|
|
|
|
|
// Link the three list nodes together
|
|
|
|
|
node1.next = SomeNode(node2);
|
|
|
|
|
node2.prev = SomeNode(node1);
|
|
|
|
|
node2.next = SomeNode(node3);
|
|
|
|
|
node3.prev = SomeNode(node2);
|
|
|
|
|
~~~
|
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
Managed boxes never cross task boundaries.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
> ***Note:*** Currently, the Rust compiler generates code to reclaim
|
|
|
|
|
> managed boxes through reference counting and a cycle collector, but
|
|
|
|
|
> we will switch to a tracing garbage collector eventually.
|
2012-07-09 23:02:36 -05:00
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
## Owned boxes
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
In contrast with managed boxes, owned boxes have a single owning
|
|
|
|
|
memory slot and thus two owned boxes may not refer to the same
|
|
|
|
|
memory. All owned boxes across all tasks are allocated on a single
|
2012-11-11 10:19:40 -06:00
|
|
|
|
_exchange heap_, where their uniquely-owned nature allows tasks to
|
2012-10-10 22:52:20 -05:00
|
|
|
|
exchange them efficiently.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
Because owned boxes are uniquely owned, copying them requires allocating
|
2012-09-23 20:45:42 -05:00
|
|
|
|
a new owned box and duplicating the contents. Copying owned boxes
|
|
|
|
|
is expensive so the compiler will complain if you do so without writing
|
|
|
|
|
the word `copy`.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
let x = ~10;
|
|
|
|
|
let y = x; // error: copying a non-implicitly copyable type
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-11-11 10:19:40 -06:00
|
|
|
|
If you really want to copy an owned box you must say so explicitly.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
let x = ~10;
|
|
|
|
|
let y = copy x;
|
2012-10-04 14:41:45 -05:00
|
|
|
|
|
|
|
|
|
let z = *x + *y;
|
2012-10-04 19:08:35 -05:00
|
|
|
|
assert z == 20;
|
2012-07-07 18:23:10 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
This is where the 'move' operator comes in. It is similar to `copy`,
|
|
|
|
|
but it de-initializes its source. Thus, the owned box can move from
|
|
|
|
|
`x` to `y`, without violating the constraint that it only has a single
|
|
|
|
|
owner (using assignment instead of the move operator would, in
|
|
|
|
|
principle, copy the box).
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-04 19:08:35 -05:00
|
|
|
|
~~~~ {.xfail-test}
|
2012-07-07 18:23:10 -05:00
|
|
|
|
let x = ~10;
|
2012-09-23 20:45:42 -05:00
|
|
|
|
let y = move x;
|
2012-10-04 14:41:45 -05:00
|
|
|
|
|
|
|
|
|
let z = *x + *y; // would cause an error: use of moved variable: `x`
|
2012-07-07 18:23:10 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
Owned boxes, when they do not contain any managed boxes, can be sent
|
2012-07-07 18:23:10 -05:00
|
|
|
|
to other tasks. The sending task will give up ownership of the box,
|
|
|
|
|
and won't be able to access it afterwards. The receiving task will
|
|
|
|
|
become the sole owner of the box.
|
|
|
|
|
|
|
|
|
|
## Borrowed pointers
|
|
|
|
|
|
|
|
|
|
Rust borrowed pointers are a general purpose reference/pointer type,
|
|
|
|
|
similar to the C++ reference type, but guaranteed to point to valid
|
2012-11-11 10:19:40 -06:00
|
|
|
|
memory. In contrast with owned pointers, where the holder of an owned
|
2012-07-07 18:23:10 -05:00
|
|
|
|
pointer is the owner of the pointed-to memory, borrowed pointers never
|
|
|
|
|
imply ownership. Pointers may be borrowed from any type, in which case
|
|
|
|
|
the pointer is guaranteed not to outlive the value it points to.
|
|
|
|
|
|
2012-09-24 21:11:48 -05:00
|
|
|
|
As an example, consider a simple struct type, `Point`:
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-09-24 21:11:48 -05:00
|
|
|
|
~~~
|
|
|
|
|
struct Point {
|
|
|
|
|
x: float, y: float
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
We can use this simple definition to allocate points in many different
|
|
|
|
|
ways. For example, in this code, each of these three local variables
|
|
|
|
|
contains a point, but allocated in a different location:
|
2012-07-07 18:27:59 -05:00
|
|
|
|
|
2012-09-24 21:11:48 -05:00
|
|
|
|
~~~
|
|
|
|
|
# struct Point { x: float, y: float }
|
|
|
|
|
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
|
2012-11-11 10:19:40 -06:00
|
|
|
|
let managed_box : @Point = @Point {x: 5.0, y: 1.0};
|
|
|
|
|
let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};
|
2012-09-24 21:11:48 -05:00
|
|
|
|
~~~
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-09-24 21:11:48 -05:00
|
|
|
|
Suppose we wanted to write a procedure that computed the distance
|
|
|
|
|
between any two points, no matter where they were stored. For example,
|
|
|
|
|
we might like to compute the distance between `on_the_stack` and
|
2012-11-11 10:19:40 -06:00
|
|
|
|
`managed_box`, or between `managed_box` and `owned_box`. One option is
|
2012-09-24 21:11:48 -05:00
|
|
|
|
to define a function that takes two arguments of type point—that is,
|
|
|
|
|
it takes the points by value. But this will cause the points to be
|
|
|
|
|
copied when we call the function. For points, this is probably not so
|
|
|
|
|
bad, but often copies are expensive or, worse, if there are mutable
|
|
|
|
|
fields, they can change the semantics of your program. So we’d like to
|
|
|
|
|
define a function that takes the points by pointer. We can use
|
|
|
|
|
borrowed pointers to do this:
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-09-24 21:11:48 -05:00
|
|
|
|
~~~
|
|
|
|
|
# struct Point { x: float, y: float }
|
|
|
|
|
# fn sqrt(f: float) -> float { 0f }
|
|
|
|
|
fn compute_distance(p1: &Point, p2: &Point) -> float {
|
|
|
|
|
let x_d = p1.x - p2.x;
|
|
|
|
|
let y_d = p1.y - p2.y;
|
|
|
|
|
sqrt(x_d * x_d + y_d * y_d)
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
2012-09-24 21:11:48 -05:00
|
|
|
|
~~~
|
|
|
|
|
|
|
|
|
|
Now we can call `compute_distance()` in various ways:
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
# struct Point{ x: float, y: float };
|
|
|
|
|
# let on_the_stack : Point = Point {x: 3.0, y: 4.0};
|
2012-11-11 10:19:40 -06:00
|
|
|
|
# let managed_box : @Point = @Point {x: 5.0, y: 1.0};
|
|
|
|
|
# let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};
|
2012-09-24 21:11:48 -05:00
|
|
|
|
# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }
|
2012-11-11 10:19:40 -06:00
|
|
|
|
compute_distance(&on_the_stack, managed_box);
|
|
|
|
|
compute_distance(managed_box, owned_box);
|
2012-09-24 21:11:48 -05:00
|
|
|
|
~~~
|
|
|
|
|
|
|
|
|
|
Here the `&` operator is used to take the address of the variable
|
2012-09-26 18:41:14 -05:00
|
|
|
|
`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
|
2012-09-24 21:11:48 -05:00
|
|
|
|
value. We also call this _borrowing_ the local variable
|
|
|
|
|
`on_the_stack`, because we are created an alias: that is, another
|
|
|
|
|
route to the same data.
|
|
|
|
|
|
2012-11-11 10:19:40 -06:00
|
|
|
|
In the case of the boxes `managed_box` and `owned_box`, however, no
|
2012-09-24 21:11:48 -05:00
|
|
|
|
explicit action is necessary. The compiler will automatically convert
|
|
|
|
|
a box like `@point` or `~point` to a borrowed pointer like
|
|
|
|
|
`&point`. This is another form of borrowing; in this case, the
|
2012-11-11 10:19:40 -06:00
|
|
|
|
contents of the managed/owned box is being lent out.
|
2012-09-24 21:11:48 -05:00
|
|
|
|
|
|
|
|
|
Whenever a value is borrowed, there are some limitations on what you
|
|
|
|
|
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, nor
|
|
|
|
|
will you be permitted to take actions that might cause the borrowed
|
|
|
|
|
value to be freed or to change its type. This rule should make
|
|
|
|
|
intuitive sense: you must wait for a borrowed value to be returned
|
|
|
|
|
(that is, for the borrowed pointer to go out of scope) before you can
|
|
|
|
|
make full use of it again.
|
|
|
|
|
|
|
|
|
|
For a more in-depth explanation of borrowed pointers, read the
|
|
|
|
|
[borrowed pointer tutorial][borrowtut].
|
|
|
|
|
|
|
|
|
|
[borrowtut]: tutorial-borrowed-ptr.html
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-05 20:39:09 -05:00
|
|
|
|
## Dereferencing pointers
|
|
|
|
|
|
|
|
|
|
Rust uses the unary star operator (`*`) to access the contents of a
|
|
|
|
|
box or pointer, similarly to C.
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
let managed = @10;
|
|
|
|
|
let owned = ~20;
|
|
|
|
|
let borrowed = &30;
|
|
|
|
|
|
|
|
|
|
let sum = *managed + *owned + *borrowed;
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
|
|
Dereferenced mutable pointers may appear on the left hand side of
|
2012-10-10 22:52:20 -05:00
|
|
|
|
assignments. Such an assignment modifies the value that the pointer
|
|
|
|
|
points to.
|
2012-10-05 20:39:09 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
let managed = @mut 10;
|
|
|
|
|
let owned = ~mut 20;
|
|
|
|
|
|
|
|
|
|
let mut value = 30;
|
|
|
|
|
let borrowed = &mut value;
|
|
|
|
|
|
|
|
|
|
*managed = *owned + 10;
|
|
|
|
|
*owned = *borrowed + 100;
|
|
|
|
|
*borrowed = *managed + 1000;
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
|
|
Pointers have high operator precedence, but lower precedence than the
|
2012-10-10 22:52:20 -05:00
|
|
|
|
dot operator used for field and method access. This precedence order
|
|
|
|
|
can sometimes make code awkward and parenthesis-filled.
|
2012-10-05 20:39:09 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
# struct Point { x: float, y: float }
|
|
|
|
|
# enum Shape { Rectangle(Point, Point) }
|
|
|
|
|
# impl Shape { fn area() -> int { 0 } }
|
|
|
|
|
let start = @Point { x: 10f, y: 20f };
|
|
|
|
|
let end = ~Point { x: (*start).x + 100f, y: (*start).y + 100f };
|
|
|
|
|
let rect = &Rectangle(*start, *end);
|
|
|
|
|
let area = (*rect).area();
|
|
|
|
|
~~~
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
To combat this ugliness the dot operator applies _automatic pointer
|
|
|
|
|
dereferencing_ to the receiver (the value on the left hand side of the
|
|
|
|
|
dot), so in most cases, explicitly dereferencing the receiver is not necessary.
|
2012-10-05 20:39:09 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
# struct Point { x: float, y: float }
|
|
|
|
|
# enum Shape { Rectangle(Point, Point) }
|
|
|
|
|
# impl Shape { fn area() -> int { 0 } }
|
|
|
|
|
let start = @Point { x: 10f, y: 20f };
|
|
|
|
|
let end = ~Point { x: start.x + 100f, y: start.y + 100f };
|
|
|
|
|
let rect = &Rectangle(*start, *end);
|
|
|
|
|
let area = rect.area();
|
|
|
|
|
~~~
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
You can write an expression that dereferences any number of pointers
|
|
|
|
|
automatically. For example, if you felt inclined, you could write
|
|
|
|
|
something silly like
|
2012-10-05 20:39:09 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
# struct Point { x: float, y: float }
|
|
|
|
|
let point = &@~Point { x: 10f, y: 20f };
|
|
|
|
|
io::println(fmt!("%f", point.x));
|
|
|
|
|
~~~
|
|
|
|
|
|
2012-10-10 22:52:20 -05:00
|
|
|
|
The indexing operator (`[]`) also auto-dereferences.
|
2012-10-05 20:39:09 -05:00
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
# Vectors and strings
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-10 23:06:22 -05:00
|
|
|
|
A vector is a contiguous section of memory containing zero or more
|
2012-07-09 23:06:22 -05:00
|
|
|
|
values of the same type. Like other types in Rust, vectors can be
|
2012-09-23 20:45:42 -05:00
|
|
|
|
stored on the stack, the local heap, or the exchange heap. Borrowed
|
|
|
|
|
pointers to vectors are also called 'slices'.
|
2012-07-07 19:31:39 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
2012-10-07 03:06:07 -05:00
|
|
|
|
# enum Crayon {
|
|
|
|
|
# Almond, AntiqueBrass, Apricot,
|
|
|
|
|
# Aquamarine, Asparagus, AtomicTangerine,
|
|
|
|
|
# BananaMania, Beaver, Bittersweet,
|
|
|
|
|
# Black, BlizzardBlue, Blue
|
|
|
|
|
# }
|
2012-09-23 20:45:42 -05:00
|
|
|
|
// A fixed-size stack vector
|
|
|
|
|
let stack_crayons: [Crayon * 3] = [Almond, AntiqueBrass, Apricot];
|
|
|
|
|
|
|
|
|
|
// A borrowed pointer to stack allocated vector
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let stack_crayons: &[Crayon] = &[Aquamarine, Asparagus, AtomicTangerine];
|
2012-09-23 20:45:42 -05:00
|
|
|
|
|
|
|
|
|
// A local heap (managed) vector of crayons
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let local_crayons: @[Crayon] = @[BananaMania, Beaver, Bittersweet];
|
2012-09-23 20:45:42 -05:00
|
|
|
|
|
|
|
|
|
// An exchange heap (owned) vector of crayons
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let exchange_crayons: ~[Crayon] = ~[Black, BlizzardBlue, Blue];
|
2012-07-07 19:31:39 -05:00
|
|
|
|
~~~
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
The `+` operator means concatenation when applied to vector types.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# enum Crayon { Almond, AntiqueBrass, Apricot,
|
|
|
|
|
# Aquamarine, Asparagus, AtomicTangerine,
|
|
|
|
|
# BananaMania, Beaver, Bittersweet };
|
2012-07-07 19:31:39 -05:00
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let my_crayons = ~[Almond, AntiqueBrass, Apricot];
|
|
|
|
|
let your_crayons = ~[BananaMania, Beaver, Bittersweet];
|
|
|
|
|
|
|
|
|
|
// Add two vectors to create a new one
|
|
|
|
|
let our_crayons = my_crayons + your_crayons;
|
|
|
|
|
|
2012-10-07 03:06:07 -05:00
|
|
|
|
// += will append to a vector, provided it lives in a mutable slot
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let mut my_crayons = move my_crayons;
|
|
|
|
|
my_crayons += your_crayons;
|
2012-07-07 18:23:10 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
> ***Note:*** The above examples of vector addition use owned
|
|
|
|
|
> vectors. Some operations on slices and stack vectors are
|
2012-10-10 23:06:22 -05:00
|
|
|
|
> not yet well-supported. Owned vectors are often the most
|
2012-10-04 19:58:13 -05:00
|
|
|
|
> usable.
|
|
|
|
|
|
2012-10-10 23:06:22 -05:00
|
|
|
|
Square brackets denote indexing into a vector:
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-07-07 19:31:39 -05:00
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# enum Crayon { Almond, AntiqueBrass, Apricot,
|
|
|
|
|
# Aquamarine, Asparagus, AtomicTangerine,
|
|
|
|
|
# BananaMania, Beaver, Bittersweet };
|
2012-10-04 19:58:13 -05:00
|
|
|
|
# fn draw_scene(c: Crayon) { }
|
|
|
|
|
let crayons: [Crayon * 3] = [BananaMania, Beaver, Bittersweet];
|
|
|
|
|
match crayons[0] {
|
|
|
|
|
Bittersweet => draw_scene(crayons[0]),
|
|
|
|
|
_ => ()
|
|
|
|
|
}
|
2012-07-07 19:31:39 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
The elements of a vector _inherit the mutability of the vector_,
|
2012-10-10 23:06:22 -05:00
|
|
|
|
and as such, individual elements may not be reassigned when the
|
2012-10-04 19:58:13 -05:00
|
|
|
|
vector lives in an immutable slot.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
~~~ {.xfail-test}
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# enum Crayon { Almond, AntiqueBrass, Apricot,
|
|
|
|
|
# Aquamarine, Asparagus, AtomicTangerine,
|
|
|
|
|
# BananaMania, Beaver, Bittersweet };
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let crayons: ~[Crayon] = ~[BananaMania, Beaver, Bittersweet];
|
2012-07-07 19:31:39 -05:00
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
crayons[0] = Apricot; // ERROR: Can't assign to immutable vector
|
|
|
|
|
~~~
|
2012-07-07 19:31:39 -05:00
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
Moving it into a mutable slot makes the elements assignable.
|
2012-07-07 19:31:39 -05:00
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# enum Crayon { Almond, AntiqueBrass, Apricot,
|
|
|
|
|
# Aquamarine, Asparagus, AtomicTangerine,
|
|
|
|
|
# BananaMania, Beaver, Bittersweet };
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let crayons: ~[Crayon] = ~[BananaMania, Beaver, Bittersweet];
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
// Put the vector into a mutable slot
|
|
|
|
|
let mut mutable_crayons = move crayons;
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
// Now it's mutable to the bone
|
|
|
|
|
mutable_crayons[0] = Apricot;
|
|
|
|
|
~~~
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
2012-10-04 19:58:13 -05:00
|
|
|
|
This is a simple example of Rust's _dual-mode data structures_, also
|
|
|
|
|
referred to as _freezing and thawing_.
|
2012-09-23 20:45:42 -05:00
|
|
|
|
|
2012-10-10 23:06:22 -05:00
|
|
|
|
Strings are implemented with vectors of `u8`, though they have a
|
|
|
|
|
distinct type. They support most of the same allocation options as
|
|
|
|
|
vectors, though the string literal without a storage sigil (for
|
|
|
|
|
example, `"foo"`) is treated differently than a comparable vector
|
|
|
|
|
(`[foo]`). Whereas plain vectors are stack-allocated fixed-length
|
|
|
|
|
vectors, plain strings are region pointers to read-only
|
|
|
|
|
memory. All strings are immutable.
|
2012-09-23 20:45:42 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
// A plain string is a slice to read-only (static) memory
|
|
|
|
|
let stack_crayons: &str = "Almond, AntiqueBrass, Apricot";
|
|
|
|
|
|
2012-10-04 14:41:45 -05:00
|
|
|
|
// The same thing, but with the `&`
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let stack_crayons: &str = &"Aquamarine, Asparagus, AtomicTangerine";
|
2012-09-23 20:45:42 -05:00
|
|
|
|
|
|
|
|
|
// A local heap (managed) string
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let local_crayons: @str = @"BananMania, Beaver, Bittersweet";
|
2012-09-23 20:45:42 -05:00
|
|
|
|
|
|
|
|
|
// An exchange heap (owned) string
|
2012-10-04 19:58:13 -05:00
|
|
|
|
let exchange_crayons: ~str = ~"Black, BlizzardBlue, Blue";
|
2012-09-23 20:45:42 -05:00
|
|
|
|
~~~
|
2012-07-07 19:54:13 -05:00
|
|
|
|
|
|
|
|
|
Both vectors and strings support a number of useful
|
2012-10-04 19:58:13 -05:00
|
|
|
|
[methods](#functions-and-methods), defined in [`core::vec`]
|
|
|
|
|
and [`core::str`]. Here are some examples.
|
|
|
|
|
|
|
|
|
|
[`core::vec`]: core/vec.html
|
|
|
|
|
[`core::str`]: core/str.html
|
2012-07-07 19:54:13 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
2012-09-05 14:39:16 -05:00
|
|
|
|
# use io::println;
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# enum Crayon {
|
|
|
|
|
# Almond, AntiqueBrass, Apricot,
|
|
|
|
|
# Aquamarine, Asparagus, AtomicTangerine,
|
|
|
|
|
# BananaMania, Beaver, Bittersweet
|
2012-07-07 19:54:13 -05:00
|
|
|
|
# }
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# fn unwrap_crayon(c: Crayon) -> int { 0 }
|
2012-07-07 19:54:13 -05:00
|
|
|
|
# fn eat_crayon_wax(i: int) { }
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# fn store_crayon_in_nasal_cavity(i: uint, c: Crayon) { }
|
2012-10-12 18:41:16 -05:00
|
|
|
|
# fn crayon_to_str(c: Crayon) -> &str { "" }
|
2012-07-07 19:54:13 -05:00
|
|
|
|
|
2012-10-12 20:47:46 -05:00
|
|
|
|
let crayons = [Almond, AntiqueBrass, Apricot];
|
2012-07-07 19:54:13 -05:00
|
|
|
|
|
|
|
|
|
// Check the length of the vector
|
|
|
|
|
assert crayons.len() == 3;
|
|
|
|
|
assert !crayons.is_empty();
|
|
|
|
|
|
2012-09-18 23:41:37 -05:00
|
|
|
|
// Iterate over a vector, obtaining a pointer to each element
|
2012-07-07 19:54:13 -05:00
|
|
|
|
for crayons.each |crayon| {
|
2012-09-19 20:59:48 -05:00
|
|
|
|
let delicious_crayon_wax = unwrap_crayon(*crayon);
|
2012-07-07 19:54:13 -05:00
|
|
|
|
eat_crayon_wax(delicious_crayon_wax);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Map vector elements
|
2012-09-21 20:43:30 -05:00
|
|
|
|
let crayon_names = crayons.map(|v| crayon_to_str(*v));
|
2012-07-07 19:54:13 -05:00
|
|
|
|
let favorite_crayon_name = crayon_names[0];
|
|
|
|
|
|
|
|
|
|
// Remove whitespace from before and after the string
|
|
|
|
|
let new_favorite_crayon_name = favorite_crayon_name.trim();
|
|
|
|
|
|
|
|
|
|
if favorite_crayon_name.len() > 5 {
|
|
|
|
|
// Create a substring
|
|
|
|
|
println(favorite_crayon_name.substr(0, 5));
|
|
|
|
|
}
|
|
|
|
|
~~~
|
|
|
|
|
|
2012-07-07 18:23:10 -05:00
|
|
|
|
# Closures
|
|
|
|
|
|
2012-07-07 20:15:59 -05:00
|
|
|
|
Named functions, like those we've seen so far, may not refer to local
|
2012-10-10 23:06:22 -05:00
|
|
|
|
variables declared outside the function: they do not close over their
|
|
|
|
|
environment (sometimes referred to as "capturing" variables in their
|
|
|
|
|
environment). For example, you couldn't write the following:
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~ {.ignore}
|
|
|
|
|
let foo = 10;
|
|
|
|
|
|
|
|
|
|
fn bar() -> int {
|
2012-08-01 19:30:05 -05:00
|
|
|
|
return foo; // `bar` cannot refer to `foo`
|
2012-07-07 18:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
Rust also supports _closures_, functions that can access variables in
|
|
|
|
|
the enclosing scope.
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-05 14:39:16 -05:00
|
|
|
|
# use println = io::println;
|
2012-07-07 18:23:10 -05:00
|
|
|
|
fn call_closure_with_ten(b: fn(int)) { b(10); }
|
|
|
|
|
|
|
|
|
|
let captured_var = 20;
|
2012-08-22 19:44:14 -05:00
|
|
|
|
let closure = |arg| println(fmt!("captured_var=%d, arg=%d", captured_var, arg));
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
call_closure_with_ten(closure);
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 23:06:22 -05:00
|
|
|
|
Closures begin with the argument list between vertical bars and are followed by
|
2012-07-07 20:15:59 -05:00
|
|
|
|
a single expression. The types of the arguments are generally omitted,
|
|
|
|
|
as is the return type, because the compiler can almost always infer
|
2012-10-10 23:06:22 -05:00
|
|
|
|
them. In the rare case where the compiler needs assistance, though, the
|
2012-07-07 20:15:59 -05:00
|
|
|
|
arguments and return types may be annotated.
|
2012-07-07 18:23:10 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-07-14 00:57:48 -05:00
|
|
|
|
# type mygoodness = fn(~str) -> ~str; type what_the = int;
|
2012-07-07 18:23:10 -05:00
|
|
|
|
let bloop = |well, oh: mygoodness| -> what_the { fail oh(well) };
|
2012-07-01 21:20:43 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
There are several forms of closure, each with its own role. The most
|
2012-10-12 19:48:45 -05:00
|
|
|
|
common, called a _stack closure_, has type `&fn` and can directly
|
2012-07-02 18:27:53 -05:00
|
|
|
|
access local variables in the enclosing scope.
|
2012-07-01 21:20:43 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
let mut max = 0;
|
2012-10-05 21:10:41 -05:00
|
|
|
|
[1, 2, 3].map(|x| if *x > max { max = *x });
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-07-01 21:20:43 -05:00
|
|
|
|
Stack closures are very efficient because their environment is
|
|
|
|
|
allocated on the call stack and refers by pointer to captured
|
|
|
|
|
locals. To ensure that stack closures never outlive the local
|
2012-10-10 23:06:22 -05:00
|
|
|
|
variables to which they refer, stack closures are not
|
|
|
|
|
first-class. That is, they can only be used in argument position; they
|
|
|
|
|
cannot be stored in data structures or returned from
|
|
|
|
|
functions. Despite these limitations, stack closures are used
|
2012-07-01 21:20:43 -05:00
|
|
|
|
pervasively in Rust code.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
## Managed closures
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-01-20 11:14:30 -06:00
|
|
|
|
When you need to store a closure in a data structure, a stack closure
|
|
|
|
|
will not do, since the compiler will refuse to let you store it. For
|
|
|
|
|
this purpose, Rust provides a type of closure that has an arbitrary
|
2012-10-12 19:48:45 -05:00
|
|
|
|
lifetime, written `@fn` (boxed closure, analogous to the `@` pointer
|
2012-10-10 23:06:22 -05:00
|
|
|
|
type described earlier). This type of closure *is* first-class.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
A managed closure does not directly access its environment, but merely
|
2012-01-19 05:51:20 -06:00
|
|
|
|
copies out the values that it closes over into a private data
|
|
|
|
|
structure. This means that it can not assign to these variables, and
|
2012-10-10 23:06:22 -05:00
|
|
|
|
cannot observe updates to them.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
This code creates a closure that adds a given string to its argument,
|
|
|
|
|
returns it from a function, and then calls it:
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-10-05 21:51:36 -05:00
|
|
|
|
# extern mod std;
|
2012-10-12 19:48:45 -05:00
|
|
|
|
fn mk_appender(suffix: ~str) -> @fn(~str) -> ~str {
|
|
|
|
|
// The compiler knows that we intend this closure to be of type @fn
|
|
|
|
|
return |s| s + suffix;
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
2012-07-14 00:57:48 -05:00
|
|
|
|
let shout = mk_appender(~"!");
|
|
|
|
|
io::println(shout(~"hey ho, let's go"));
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
## Owned closures
|
2012-07-03 01:04:55 -05:00
|
|
|
|
|
2012-10-12 19:48:45 -05:00
|
|
|
|
Owned closures, written `~fn` in analogy to the `~` pointer type,
|
2012-07-10 02:35:14 -05:00
|
|
|
|
hold on to things that can safely be sent between
|
2012-09-23 20:45:42 -05:00
|
|
|
|
processes. They copy the values they close over, much like managed
|
2012-10-10 23:06:22 -05:00
|
|
|
|
closures, but they also own them: that is, no other code can access
|
2012-09-23 20:45:42 -05:00
|
|
|
|
them. Owned closures are used in concurrent code, particularly
|
2012-10-11 16:10:05 -05:00
|
|
|
|
for spawning [tasks][tasks].
|
|
|
|
|
|
|
|
|
|
[tasks]: tutorial-tasks.html
|
2012-07-03 01:04:55 -05:00
|
|
|
|
|
2012-07-07 17:08:38 -05:00
|
|
|
|
## Closure compatibility
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 23:06:22 -05:00
|
|
|
|
Rust closures have a convenient subtyping property: you can pass any kind of
|
2012-01-19 05:51:20 -06:00
|
|
|
|
closure (as long as the arguments and return types match) to functions
|
2012-01-20 11:14:30 -06:00
|
|
|
|
that expect a `fn()`. Thus, when writing a higher-order function that
|
2012-10-10 23:06:22 -05:00
|
|
|
|
only calls its function argument, and does nothing else with it, you
|
|
|
|
|
should almost always declare the type of that argument as `fn()`. That way,
|
|
|
|
|
callers may pass any kind of closure.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-01-20 11:14:30 -06:00
|
|
|
|
fn call_twice(f: fn()) { f(); f(); }
|
2012-10-12 19:48:45 -05:00
|
|
|
|
let closure = || { "I'm a closure, and it doesn't matter what type I am"; };
|
|
|
|
|
fn function() { "I'm a normal function"; }
|
|
|
|
|
call_twice(closure);
|
|
|
|
|
call_twice(function);
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-09-23 20:45:42 -05:00
|
|
|
|
> ***Note:*** Both the syntax and the semantics will be changing
|
2012-10-10 23:06:22 -05:00
|
|
|
|
> in small ways. At the moment they can be unsound in some
|
2012-09-23 20:45:42 -05:00
|
|
|
|
> scenarios, particularly with non-copyable types.
|
|
|
|
|
|
2012-07-06 17:10:12 -05:00
|
|
|
|
## Do syntax
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 03:52:06 -05:00
|
|
|
|
The `do` expression provides a way to treat higher-order functions
|
|
|
|
|
(functions that take closures as arguments) as control structures.
|
2012-10-04 14:41:45 -05:00
|
|
|
|
|
2012-10-10 23:06:22 -05:00
|
|
|
|
Consider this function that iterates over a vector of
|
2012-09-18 23:41:37 -05:00
|
|
|
|
integers, passing in a pointer to each integer in the vector:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-23 20:45:42 -05:00
|
|
|
|
fn each(v: &[int], op: fn(v: &int)) {
|
2012-07-04 03:50:51 -05:00
|
|
|
|
let mut n = 0;
|
|
|
|
|
while n < v.len() {
|
2012-09-18 23:41:37 -05:00
|
|
|
|
op(&v[n]);
|
2012-07-04 03:50:51 -05:00
|
|
|
|
n += 1;
|
|
|
|
|
}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-07 03:52:06 -05:00
|
|
|
|
As an aside, the reason we pass in a *pointer* to an integer rather
|
|
|
|
|
than the integer itself is that this is how the actual `each()`
|
|
|
|
|
function for vectors works. `vec::each` though is a
|
|
|
|
|
[generic](#generics) function, so must be efficient to use for all
|
|
|
|
|
types. Passing the elements by pointer avoids copying potentially
|
|
|
|
|
large objects.
|
|
|
|
|
|
|
|
|
|
As a caller, if we use a closure to provide the final operator
|
|
|
|
|
argument, we can write it in a way that has a pleasant, block-like
|
|
|
|
|
structure.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-23 20:45:42 -05:00
|
|
|
|
# fn each(v: &[int], op: fn(v: &int)) { }
|
2012-10-07 03:52:06 -05:00
|
|
|
|
# fn do_some_work(i: &int) { }
|
2012-10-12 20:47:46 -05:00
|
|
|
|
each([1, 2, 3], |n| {
|
2012-10-07 03:52:06 -05:00
|
|
|
|
do_some_work(n);
|
2012-07-03 01:04:55 -05:00
|
|
|
|
});
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-07-04 03:50:51 -05:00
|
|
|
|
This is such a useful pattern that Rust has a special form of function
|
|
|
|
|
call that can be written more like a built-in control structure:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-23 20:45:42 -05:00
|
|
|
|
# fn each(v: &[int], op: fn(v: &int)) { }
|
2012-10-07 03:52:06 -05:00
|
|
|
|
# fn do_some_work(i: &int) { }
|
2012-10-12 20:47:46 -05:00
|
|
|
|
do each([1, 2, 3]) |n| {
|
2012-10-07 03:52:06 -05:00
|
|
|
|
do_some_work(n);
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-07-04 03:50:51 -05:00
|
|
|
|
The call is prefixed with the keyword `do` and, instead of writing the
|
2012-10-10 23:06:22 -05:00
|
|
|
|
final closure inside the argument list, it appears outside of the
|
|
|
|
|
parentheses, where it looks more like a typical block of
|
2012-10-04 14:41:45 -05:00
|
|
|
|
code.
|
2012-07-04 03:50:51 -05:00
|
|
|
|
|
2012-10-10 23:06:22 -05:00
|
|
|
|
`do` is a convenient way to create tasks with the `task::spawn`
|
2012-10-12 19:48:45 -05:00
|
|
|
|
function. `spawn` has the signature `spawn(fn: ~fn())`. In other
|
2012-10-10 23:06:22 -05:00
|
|
|
|
words, it is a function that takes an owned closure that takes no
|
|
|
|
|
arguments.
|
2012-07-04 03:50:51 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-05 14:39:16 -05:00
|
|
|
|
use task::spawn;
|
2012-07-04 03:50:51 -05:00
|
|
|
|
|
|
|
|
|
do spawn() || {
|
2012-08-22 19:44:14 -05:00
|
|
|
|
debug!("I'm a task, whatever");
|
2012-07-04 03:50:51 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-07 03:52:06 -05:00
|
|
|
|
Look at all those bars and parentheses - that's two empty argument
|
|
|
|
|
lists back to back. Since that is so unsightly, empty argument lists
|
|
|
|
|
may be omitted from `do` expressions.
|
2012-07-04 03:50:51 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-05 14:39:16 -05:00
|
|
|
|
# use task::spawn;
|
2012-07-04 03:50:51 -05:00
|
|
|
|
do spawn {
|
2012-08-22 19:44:14 -05:00
|
|
|
|
debug!("Kablam!");
|
2012-07-04 03:50:51 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-07-06 17:10:12 -05:00
|
|
|
|
## For loops
|
2012-04-18 08:41:33 -05:00
|
|
|
|
|
2012-10-10 23:06:22 -05:00
|
|
|
|
The most common way to express iteration in Rust is with a `for`
|
|
|
|
|
loop. Like `do`, `for` is a nice syntax for describing control flow
|
|
|
|
|
with closures. Additionally, within a `for` loop, `break`, `loop`,
|
|
|
|
|
and `return` work just as they do with `while` and `loop`.
|
2012-04-18 08:41:33 -05:00
|
|
|
|
|
2012-07-04 03:50:51 -05:00
|
|
|
|
Consider again our `each` function, this time improved to
|
|
|
|
|
break early when the iteratee returns `false`:
|
2012-07-02 18:27:53 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-23 20:45:42 -05:00
|
|
|
|
fn each(v: &[int], op: fn(v: &int) -> bool) {
|
2012-07-02 18:27:53 -05:00
|
|
|
|
let mut n = 0;
|
|
|
|
|
while n < v.len() {
|
2012-09-18 23:41:37 -05:00
|
|
|
|
if !op(&v[n]) {
|
2012-07-02 18:27:53 -05:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
n += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-04-18 08:41:33 -05:00
|
|
|
|
~~~~
|
2012-07-02 18:27:53 -05:00
|
|
|
|
|
|
|
|
|
And using this function to iterate over a vector:
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-05 14:39:16 -05:00
|
|
|
|
# use each = vec::each;
|
|
|
|
|
# use println = io::println;
|
2012-10-12 20:47:46 -05:00
|
|
|
|
each([2, 4, 8, 5, 16], |n| {
|
2012-09-18 23:41:37 -05:00
|
|
|
|
if *n % 2 != 0 {
|
2012-10-12 18:41:16 -05:00
|
|
|
|
println("found odd number!");
|
2012-04-18 08:41:33 -05:00
|
|
|
|
false
|
|
|
|
|
} else { true }
|
2012-06-26 15:55:56 -05:00
|
|
|
|
});
|
2012-04-18 08:41:33 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-07-04 03:50:51 -05:00
|
|
|
|
With `for`, functions like `each` can be treated more
|
2012-10-10 23:06:22 -05:00
|
|
|
|
like built-in looping structures. When calling `each`
|
2012-07-04 03:50:51 -05:00
|
|
|
|
in a `for` loop, instead of returning `false` to break
|
2012-07-06 17:46:31 -05:00
|
|
|
|
out of the loop, you just write `break`. To skip ahead
|
2012-09-26 22:28:39 -05:00
|
|
|
|
to the next iteration, write `loop`.
|
2012-04-18 08:41:33 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-05 14:39:16 -05:00
|
|
|
|
# use each = vec::each;
|
|
|
|
|
# use println = io::println;
|
2012-10-12 20:47:46 -05:00
|
|
|
|
for each([2, 4, 8, 5, 16]) |n| {
|
2012-09-18 23:41:37 -05:00
|
|
|
|
if *n % 2 != 0 {
|
2012-10-12 18:41:16 -05:00
|
|
|
|
println("found odd number!");
|
2012-04-18 08:41:33 -05:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
|
As an added bonus, you can use the `return` keyword, which is not
|
2012-07-04 03:50:51 -05:00
|
|
|
|
normally allowed in closures, in a block that appears as the body of a
|
2012-10-10 23:06:22 -05:00
|
|
|
|
`for` loop: the meaning of `return` in such a block is to return from
|
|
|
|
|
the enclosing function, not just the loop body.
|
2012-04-18 08:41:33 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-05 14:39:16 -05:00
|
|
|
|
# use each = vec::each;
|
2012-09-23 20:45:42 -05:00
|
|
|
|
fn contains(v: &[int], elt: int) -> bool {
|
2012-07-02 18:27:53 -05:00
|
|
|
|
for each(v) |x| {
|
2012-09-18 23:41:37 -05:00
|
|
|
|
if (*x == elt) { return true; }
|
2012-04-18 08:41:33 -05:00
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-07-04 03:50:51 -05:00
|
|
|
|
`for` syntax only works with stack closures.
|
|
|
|
|
|
2012-10-04 14:41:45 -05:00
|
|
|
|
> ***Note:*** This is, essentially, a special loop protocol:
|
|
|
|
|
> the keywords `break`, `loop`, and `return` work, in varying degree,
|
|
|
|
|
> with `while`, `loop`, `do`, and `for` constructs.
|
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
# Generics
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
Throughout this tutorial, we've been defining functions that act only
|
|
|
|
|
on specific data types. With type parameters we can also define
|
|
|
|
|
functions whose arguments have generic types, and which can be invoked
|
|
|
|
|
with a variety of types. Consider a generic `map` function, which
|
|
|
|
|
takes a function `function` and a vector `vector` and returns a new
|
|
|
|
|
vector consisting of the result of applying `function` to each element
|
|
|
|
|
of `vector`:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-18 23:41:37 -05:00
|
|
|
|
fn map<T, U>(vector: &[T], function: fn(v: &T) -> U) -> ~[U] {
|
2012-07-08 15:58:37 -05:00
|
|
|
|
let mut accumulator = ~[];
|
2012-09-18 23:41:37 -05:00
|
|
|
|
for vec::each(vector) |element| {
|
2012-09-26 19:33:34 -05:00
|
|
|
|
accumulator.push(function(element));
|
2012-07-09 17:28:08 -05:00
|
|
|
|
}
|
2012-09-19 00:33:49 -05:00
|
|
|
|
return (move accumulator);
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-09-23 23:07:01 -05:00
|
|
|
|
When defined with type parameters, as denoted by `<T, U>`, this
|
|
|
|
|
function can be applied to any type of vector, as long as the type of
|
2012-10-10 23:29:25 -05:00
|
|
|
|
`function`'s argument and the type of the vector's contents agree with
|
2012-09-23 23:07:01 -05:00
|
|
|
|
each other.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-07-09 17:28:08 -05:00
|
|
|
|
Inside a generic function, the names of the type parameters
|
2012-10-10 23:29:25 -05:00
|
|
|
|
(capitalized by convention) stand for opaque types. All you can do
|
|
|
|
|
with instances of these types is pass them around: you can't apply any
|
|
|
|
|
operations to them or pattern-match on them. Note that instances of
|
|
|
|
|
generic types are often passed by pointer. For example, the parameter
|
|
|
|
|
`function()` is supplied with a pointer to a value of type `T` and not
|
|
|
|
|
a value of type `T` itself. This ensures that the function works with
|
|
|
|
|
the broadest set of types possible, since some types are expensive or
|
|
|
|
|
illegal to copy and pass by value.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-08-31 19:36:40 -05:00
|
|
|
|
Generic `type`, `struct`, and `enum` declarations follow the same pattern:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-23 23:07:01 -05:00
|
|
|
|
# use std::map::HashMap;
|
|
|
|
|
type Set<T> = HashMap<T, ()>;
|
|
|
|
|
|
2012-08-31 19:36:40 -05:00
|
|
|
|
struct Stack<T> {
|
|
|
|
|
elements: ~[mut T]
|
|
|
|
|
}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-08-31 19:36:40 -05:00
|
|
|
|
enum Maybe<T> {
|
|
|
|
|
Just(T),
|
|
|
|
|
Nothing
|
|
|
|
|
}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
These declarations can be instantiated to valid types like `Set<int>`,
|
|
|
|
|
`Stack<int>` and `Maybe<int>`.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
The Rust compiler compiles generic functions very efficiently by
|
|
|
|
|
*monomorphizing* them. *Monomorphization* is a fancy name for a simple
|
|
|
|
|
idea: generate a separate copy of each generic function at each call
|
|
|
|
|
site where it is called, a copy that is specialized to the argument
|
|
|
|
|
types and can thus be optimized specifically for them. In this
|
|
|
|
|
respect, Rust's generics have similar performance characteristics to
|
|
|
|
|
C++ templates.
|
2012-09-23 23:07:01 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
## Traits
|
2012-09-23 23:07:01 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
Within a generic function the operations available on generic types
|
|
|
|
|
are very limited. After all, since the function doesn't know what
|
|
|
|
|
types it is operating on, it can't safely modify or query their
|
|
|
|
|
values. This is where _traits_ come into play. Traits are Rust's most
|
|
|
|
|
powerful tool for writing polymorphic code. Java developers will see
|
2012-10-10 23:29:25 -05:00
|
|
|
|
them as similar to Java interfaces, and Haskellers will notice their
|
|
|
|
|
similarities to type classes. Rust's traits are a form of *bounded
|
|
|
|
|
polymorphism*: a trait is a way of limiting the set of possible types
|
|
|
|
|
that a type parameter could refer to.
|
|
|
|
|
|
|
|
|
|
As motivation, let us consider copying in Rust. The `copy` operation
|
|
|
|
|
is not defined for all Rust types. One reason is user-defined
|
|
|
|
|
destructors: copying a type that has a destructor could result in the
|
|
|
|
|
destructor running multiple times. Therefore, types with user-defined
|
|
|
|
|
destructors cannot be copied, either implicitly or explicitly, and
|
|
|
|
|
neither can types that own other types containing destructors (see the
|
|
|
|
|
section on [structs](#structs) for the actual mechanism for defining
|
|
|
|
|
destructors).
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
This complicates handling of generic functions. If you have a type
|
|
|
|
|
parameter `T`, can you copy values of that type? In Rust, you can't,
|
2012-09-24 19:37:33 -05:00
|
|
|
|
and if you try to run the following code the compiler will complain.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
~~~~ {.xfail-test}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
// This does not compile
|
2012-09-24 19:37:33 -05:00
|
|
|
|
fn head_bad<T>(v: &[T]) -> T {
|
|
|
|
|
v[0] // error: copying a non-copyable value
|
2012-09-23 23:07:01 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
However, we can tell the compiler that the `head` function is only for
|
|
|
|
|
copyable types: that is, those that have the `Copy` trait.
|
2012-09-24 19:37:33 -05:00
|
|
|
|
|
2012-09-23 23:07:01 -05:00
|
|
|
|
~~~~
|
2012-01-19 05:51:20 -06:00
|
|
|
|
// This does
|
2012-09-24 19:37:33 -05:00
|
|
|
|
fn head<T: Copy>(v: &[T]) -> T {
|
|
|
|
|
v[0]
|
2012-09-23 23:07:01 -05:00
|
|
|
|
}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
This says that we can call `head` on any type `T` as long as that type
|
|
|
|
|
implements the `Copy` trait. When instantiating a generic function,
|
|
|
|
|
you can only instantiate it with types that implement the correct
|
2012-10-10 23:29:25 -05:00
|
|
|
|
trait, so you could not apply `head` to a type with a
|
|
|
|
|
destructor. (`Copy` is a special trait that is built in to the
|
|
|
|
|
compiler, making it possible for the compiler to enforce this
|
|
|
|
|
restriction.)
|
2012-09-23 23:07:01 -05:00
|
|
|
|
|
|
|
|
|
While most traits can be defined and implemented by user code, three
|
2012-09-24 19:37:33 -05:00
|
|
|
|
traits are automatically derived and implemented for all applicable
|
|
|
|
|
types by the compiler, and may not be overridden:
|
2012-09-23 23:07:01 -05:00
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
* `Copy` - Types that can be copied: either implicitly, or explicitly with the
|
2012-11-05 19:50:01 -06:00
|
|
|
|
`copy` operator. All types are copyable unless they have destructors or
|
|
|
|
|
contain types with destructors.
|
2012-09-23 23:07:01 -05:00
|
|
|
|
|
|
|
|
|
* `Send` - Sendable (owned) types. All types are sendable unless they
|
|
|
|
|
contain managed boxes, managed closures, or otherwise managed
|
|
|
|
|
types. Sendable types may or may not be copyable.
|
|
|
|
|
|
|
|
|
|
* `Const` - Constant (immutable) types. These are types that do not contain
|
|
|
|
|
mutable fields.
|
|
|
|
|
|
|
|
|
|
> ***Note:*** These three traits were referred to as 'kinds' in earlier
|
|
|
|
|
> iterations of the language, and often still are.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-11-05 19:50:01 -06:00
|
|
|
|
There is also a special trait known as `Drop`. This trait defines one method
|
|
|
|
|
called `finalize`, which is automatically called when value of the a type that
|
|
|
|
|
implements this trait is destroyed, either because the value went out of scope
|
|
|
|
|
or because the garbage collector reclaimed it.
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
struct TimeBomb {
|
|
|
|
|
explosivity: uint,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TimeBomb : Drop {
|
|
|
|
|
fn finalize() {
|
|
|
|
|
for iter::repeat(self.explosivity) {
|
|
|
|
|
io::println("blam!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
|
|
It is illegal to call `finalize` directly. Only code inserted by the compiler
|
|
|
|
|
may call it.
|
|
|
|
|
|
2012-09-23 23:07:01 -05:00
|
|
|
|
## Declaring and implementing traits
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-10-02 22:28:53 -05:00
|
|
|
|
A trait consists of a set of methods, without bodies, or may be empty,
|
|
|
|
|
as is the case with `Copy`, `Send`, and `Const`. For example, we could
|
|
|
|
|
declare the trait `Printable` for things that can be printed to the
|
|
|
|
|
console, with a single method:
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-24 19:37:33 -05:00
|
|
|
|
trait Printable {
|
|
|
|
|
fn print();
|
2012-09-07 19:12:16 -05:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-02 22:28:53 -05:00
|
|
|
|
Traits may be implemented for specific types with [impls]. An impl
|
2012-10-11 22:13:04 -05:00
|
|
|
|
that implements a trait includes the name of the trait at the start of
|
2012-10-02 22:28:53 -05:00
|
|
|
|
the definition, as in the following impls of `Printable` for `int`
|
|
|
|
|
and `~str`.
|
|
|
|
|
|
|
|
|
|
[impls]: #functions-and-methods
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-24 19:37:33 -05:00
|
|
|
|
# trait Printable { fn print(); }
|
|
|
|
|
impl int: Printable {
|
|
|
|
|
fn print() { io::println(fmt!("%d", self)) }
|
2012-09-07 19:12:16 -05:00
|
|
|
|
}
|
2012-09-24 19:37:33 -05:00
|
|
|
|
|
2012-10-12 18:41:16 -05:00
|
|
|
|
impl &str: Printable {
|
2012-09-24 19:37:33 -05:00
|
|
|
|
fn print() { io::println(self) }
|
2012-09-07 19:12:16 -05:00
|
|
|
|
}
|
2012-09-23 23:07:01 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
# 1.print();
|
2012-10-12 18:41:16 -05:00
|
|
|
|
# ("foo").print();
|
2012-09-07 19:12:16 -05:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
Methods defined in an implementation of a trait may be called just like
|
2012-10-02 22:28:53 -05:00
|
|
|
|
any other method, using dot notation, as in `1.print()`. Traits may
|
|
|
|
|
themselves contain type parameters. A trait for generalized sequence
|
|
|
|
|
types might look like the following:
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
trait Seq<T> {
|
2012-09-07 19:12:16 -05:00
|
|
|
|
fn len() -> uint;
|
2012-09-18 23:41:37 -05:00
|
|
|
|
fn iter(b: fn(v: &T));
|
2012-09-07 19:12:16 -05:00
|
|
|
|
}
|
2012-09-24 19:37:33 -05:00
|
|
|
|
|
2012-09-15 20:44:44 -05:00
|
|
|
|
impl<T> ~[T]: Seq<T> {
|
2012-09-07 19:12:16 -05:00
|
|
|
|
fn len() -> uint { vec::len(self) }
|
2012-09-18 23:41:37 -05:00
|
|
|
|
fn iter(b: fn(v: &T)) {
|
|
|
|
|
for vec::each(self) |elt| { b(elt); }
|
2012-09-07 19:12:16 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
The implementation has to explicitly declare the type parameter that
|
|
|
|
|
it binds, `T`, before using it to specify its trait type. Rust
|
|
|
|
|
requires this declaration because the `impl` could also, for example,
|
2012-10-10 23:29:25 -05:00
|
|
|
|
specify an implementation of `Seq<int>`. The trait type (appearing
|
|
|
|
|
after the colon in the `impl`) *refers* to a type, rather than
|
2012-09-24 19:37:33 -05:00
|
|
|
|
defining one.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
|
|
|
|
The type parameters bound by a trait are in scope in each of the
|
|
|
|
|
method declarations. So, re-declaring the type parameter
|
2012-10-10 23:29:25 -05:00
|
|
|
|
`T` as an explicit type parameter for `len`, in either the trait or
|
|
|
|
|
the impl, would be a compile-time error.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-09-24 19:49:04 -05:00
|
|
|
|
Within a trait definition, `self` is a special type that you can think
|
|
|
|
|
of as a type parameter. An implementation of the trait for any given
|
|
|
|
|
type `T` replaces the `self` type parameter with `T`. Simply, in a
|
|
|
|
|
trait, `self` is a type, and in an impl, `self` is a value. The
|
|
|
|
|
following trait describes types that support an equality operation:
|
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
// In a trait, `self` refers to the type implementing the trait
|
|
|
|
|
trait Eq {
|
|
|
|
|
fn equals(other: &self) -> bool;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// In an impl, self refers to the value of the receiver
|
|
|
|
|
impl int: Eq {
|
|
|
|
|
fn equals(other: &int) -> bool { *other == self }
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
Notice that in the trait definition, `equals` takes a parameter of
|
|
|
|
|
type `self`. In contrast, in the `impl`, `equals` takes a parameter of
|
|
|
|
|
type `int`, and uses `self` as the name of the receiver (analogous to
|
|
|
|
|
the `this` pointer in C++).
|
2012-09-24 19:49:04 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
## Bounded type parameters and static method dispatch
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
Traits give us a language for defining predicates on types, or
|
|
|
|
|
abstract properties that types can have. We can use this language to
|
|
|
|
|
define _bounds_ on type parameters, so that we can then operate on
|
|
|
|
|
generic types.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-24 19:37:33 -05:00
|
|
|
|
# trait Printable { fn print(); }
|
|
|
|
|
fn print_all<T: Printable>(printable_things: ~[T]) {
|
|
|
|
|
for printable_things.each |thing| {
|
|
|
|
|
thing.print();
|
|
|
|
|
}
|
2012-09-07 19:12:16 -05:00
|
|
|
|
}
|
2012-09-24 19:37:33 -05:00
|
|
|
|
~~~~
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
Declaring `T` as conforming to the `Printable` trait (as we earlier
|
|
|
|
|
did with `Copy`) makes it possible to call methods from that trait
|
|
|
|
|
on values of type `T` inside the function. It will also cause a
|
2012-09-24 19:37:33 -05:00
|
|
|
|
compile-time error when anyone tries to call `print_all` on an array
|
|
|
|
|
whose element type does not have a `Printable` implementation.
|
|
|
|
|
|
|
|
|
|
Type parameters can have multiple bounds by separating them with spaces,
|
2012-10-10 23:29:25 -05:00
|
|
|
|
as in this version of `print_all` that copies elements.
|
2012-09-24 19:37:33 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
# trait Printable { fn print(); }
|
|
|
|
|
fn print_all<T: Printable Copy>(printable_things: ~[T]) {
|
|
|
|
|
let mut i = 0;
|
|
|
|
|
while i < printable_things.len() {
|
|
|
|
|
let copy_of_thing = printable_things[0];
|
|
|
|
|
copy_of_thing.print();
|
|
|
|
|
}
|
2012-09-07 19:12:16 -05:00
|
|
|
|
}
|
2012-09-24 19:37:33 -05:00
|
|
|
|
~~~
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
Method calls to bounded type parameters are _statically dispatched_,
|
|
|
|
|
imposing no more overhead than normal function invocation, so are
|
|
|
|
|
the preferred way to use traits polymorphically.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
This usage of traits is similar to Haskell type classes.
|
|
|
|
|
|
2012-09-24 19:49:04 -05:00
|
|
|
|
## Casting to a trait type and dynamic method dispatch
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
|
|
|
|
The above allows us to define functions that polymorphically act on
|
2012-09-24 19:37:33 -05:00
|
|
|
|
values of a single unknown type that conforms to a given trait.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
However, consider this function:
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# type Circle = int; type Rectangle = int;
|
|
|
|
|
# impl int: Drawable { fn draw() {} }
|
2012-09-07 19:12:16 -05:00
|
|
|
|
# fn new_circle() -> int { 1 }
|
2012-09-24 19:37:33 -05:00
|
|
|
|
trait Drawable { fn draw(); }
|
|
|
|
|
|
2012-09-15 20:44:44 -05:00
|
|
|
|
fn draw_all<T: Drawable>(shapes: ~[T]) {
|
2012-09-07 19:12:16 -05:00
|
|
|
|
for shapes.each |shape| { shape.draw(); }
|
|
|
|
|
}
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# let c: Circle = new_circle();
|
2012-09-07 19:12:16 -05:00
|
|
|
|
# draw_all(~[c]);
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
You can call that on an array of circles, or an array of squares
|
2012-09-24 19:37:33 -05:00
|
|
|
|
(assuming those have suitable `Drawable` traits defined), but not on
|
|
|
|
|
an array containing both circles and squares. When such behavior is
|
|
|
|
|
needed, a trait name can alternately be used as a type.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
|
|
|
|
~~~~
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# trait Drawable { fn draw(); }
|
2012-10-06 17:47:57 -05:00
|
|
|
|
fn draw_all(shapes: &[@Drawable]) {
|
2012-09-07 19:12:16 -05:00
|
|
|
|
for shapes.each |shape| { shape.draw(); }
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
In this example, there is no type parameter. Instead, the `@Drawable`
|
|
|
|
|
type denotes any managed box value that implements the `Drawable`
|
|
|
|
|
trait. To construct such a value, you use the `as` operator to cast a
|
|
|
|
|
value to a trait type:
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
~~~~
|
|
|
|
|
# type Circle = int; type Rectangle = bool;
|
|
|
|
|
# trait Drawable { fn draw(); }
|
|
|
|
|
# fn new_circle() -> Circle { 1 }
|
|
|
|
|
# fn new_rectangle() -> Rectangle { true }
|
2012-10-06 17:47:57 -05:00
|
|
|
|
# fn draw_all(shapes: &[@Drawable]) {}
|
2012-09-24 19:37:33 -05:00
|
|
|
|
|
|
|
|
|
impl @Circle: Drawable { fn draw() { ... } }
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
impl @Rectangle: Drawable { fn draw() { ... } }
|
|
|
|
|
|
|
|
|
|
let c: @Circle = @new_circle();
|
|
|
|
|
let r: @Rectangle = @new_rectangle();
|
2012-10-12 20:47:46 -05:00
|
|
|
|
draw_all([c as @Drawable, r as @Drawable]);
|
2012-09-07 19:12:16 -05:00
|
|
|
|
~~~~
|
2012-09-24 19:37:33 -05:00
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
We omit the code for `new_circle` and `new_rectangle`; imagine that
|
|
|
|
|
these just return `Circle`s and `Rectangle`s with a default size. Note
|
|
|
|
|
that, like strings and vectors, trait types have dynamic size and may
|
|
|
|
|
only be referred to via one of the pointer types. That's why the `impl` is
|
|
|
|
|
defined for `@Circle` and `@Rectangle` instead of for just `Circle`
|
|
|
|
|
and `Rectangle`. Other pointer types work as well.
|
2012-09-24 19:37:33 -05:00
|
|
|
|
|
|
|
|
|
~~~{.xfail-test}
|
2012-09-15 20:44:44 -05:00
|
|
|
|
# type Circle = int; type Rectangle = int;
|
|
|
|
|
# trait Drawable { fn draw(); }
|
|
|
|
|
# impl int: Drawable { fn draw() {} }
|
2012-09-07 19:12:16 -05:00
|
|
|
|
# fn new_circle() -> int { 1 }
|
|
|
|
|
# fn new_rectangle() -> int { 2 }
|
2012-09-24 19:37:33 -05:00
|
|
|
|
// A managed trait instance
|
|
|
|
|
let boxy: @Drawable = @new_circle() as @Drawable;
|
|
|
|
|
// An owned trait instance
|
|
|
|
|
let owny: ~Drawable = ~new_circle() as ~Drawable;
|
|
|
|
|
// A borrowed trait instance
|
|
|
|
|
let stacky: &Drawable = &new_circle() as &Drawable;
|
|
|
|
|
~~~
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
> ***Note:*** Other pointer types actually _do not_ work here yet. This is
|
2012-09-24 19:37:33 -05:00
|
|
|
|
> an evolving corner of the language.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
Method calls to trait types are _dynamically dispatched_. Since the
|
|
|
|
|
compiler doesn't know specifically which functions to call at compile
|
2012-10-10 23:29:25 -05:00
|
|
|
|
time it uses a lookup table (also known as a vtable or dictionary) to
|
|
|
|
|
select the method to call at runtime.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-09-24 19:37:33 -05:00
|
|
|
|
This usage of traits is similar to Java interfaces.
|
2012-09-07 19:12:16 -05:00
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
# Modules and crates
|
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
The Rust namespace is arranged in a hierarchy of modules. Each source
|
|
|
|
|
(.rs) file represents a single module and may in turn contain
|
|
|
|
|
additional modules.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
~~~~
|
|
|
|
|
mod farm {
|
2012-10-12 18:41:16 -05:00
|
|
|
|
pub fn chicken() -> &str { "cluck cluck" }
|
|
|
|
|
pub fn cow() -> &str { "mooo" }
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
2012-10-07 00:23:16 -05:00
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
fn main() {
|
2012-03-12 22:04:27 -05:00
|
|
|
|
io::println(farm::chicken());
|
2012-01-19 05:51:20 -06:00
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
The contents of modules can be imported into the current scope
|
|
|
|
|
with the `use` keyword, optionally giving it an alias. `use`
|
|
|
|
|
may appear at the beginning of crates, `mod`s, `fn`s, and other
|
|
|
|
|
blocks.
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
# mod farm { pub fn chicken() { } }
|
|
|
|
|
# fn main() {
|
|
|
|
|
// Bring `chicken` into scope
|
|
|
|
|
use farm::chicken;
|
|
|
|
|
|
|
|
|
|
fn chicken_farmer() {
|
|
|
|
|
// The same, but name it `my_chicken`
|
|
|
|
|
use my_chicken = farm::chicken;
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
# }
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
|
|
These farm animal functions have a new keyword, `pub`, attached to
|
2012-10-10 23:29:25 -05:00
|
|
|
|
them. The `pub` keyword modifies an item's visibility, making it
|
|
|
|
|
visible outside its containing module. An expression with `::`, like
|
|
|
|
|
`farm::chicken`, can name an item outside of its containing
|
|
|
|
|
module. Items, such as those declared with `fn`, `struct`, `enum`,
|
|
|
|
|
`type`, or `const`, are module-private by default.
|
2012-10-07 00:23:16 -05:00
|
|
|
|
|
|
|
|
|
Visibility restrictions in Rust exist only at module boundaries. This
|
2012-10-10 23:29:25 -05:00
|
|
|
|
is quite different from most object-oriented languages that also
|
|
|
|
|
enforce restrictions on objects themselves. That's not to say that
|
|
|
|
|
Rust doesn't support encapsulation: both struct fields and methods can
|
|
|
|
|
be private. But this encapsulation is at the module level, not the
|
|
|
|
|
struct level. Note that fields and methods are _public_ by default.
|
2012-10-07 00:23:16 -05:00
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
mod farm {
|
|
|
|
|
# pub fn make_me_a_farm() -> farm::Farm { farm::Farm { chickens: ~[], cows: ~[], farmer: Human(0) } }
|
|
|
|
|
pub struct Farm {
|
|
|
|
|
priv mut chickens: ~[Chicken],
|
|
|
|
|
priv mut cows: ~[Cow],
|
|
|
|
|
farmer: Human
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Note - visibility modifiers on impls currently have no effect
|
|
|
|
|
impl Farm {
|
|
|
|
|
priv fn feed_chickens() { ... }
|
|
|
|
|
priv fn feed_cows() { ... }
|
|
|
|
|
fn add_chicken(c: Chicken) { ... }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn feed_animals(farm: &Farm) {
|
|
|
|
|
farm.feed_chickens();
|
|
|
|
|
farm.feed_cows();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
let f = make_me_a_farm();
|
|
|
|
|
f.add_chicken(make_me_a_chicken());
|
|
|
|
|
farm::feed_animals(&f);
|
|
|
|
|
f.farmer.rest();
|
|
|
|
|
}
|
|
|
|
|
# type Chicken = int;
|
|
|
|
|
# type Cow = int;
|
|
|
|
|
# enum Human = int;
|
|
|
|
|
# fn make_me_a_farm() -> farm::Farm { farm::make_me_a_farm() }
|
|
|
|
|
# fn make_me_a_chicken() -> Chicken { 0 }
|
|
|
|
|
# impl Human { fn rest() { } }
|
|
|
|
|
~~~
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
## Crates
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
The unit of independent compilation in Rust is the crate: rustc
|
2012-10-07 00:23:16 -05:00
|
|
|
|
compiles a single crate at a time, from which it produces either a
|
|
|
|
|
library or executable.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
When compiling a single `.rs` file, the file acts as the whole crate.
|
|
|
|
|
You can compile it with the `--lib` compiler switch to create a shared
|
|
|
|
|
library, or without, provided that your file contains a `fn main`
|
|
|
|
|
somewhere, to create an executable.
|
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
Larger crates typically span multiple files and are compiled from
|
|
|
|
|
a crate (.rc) file. Crate files contain their own syntax for loading
|
|
|
|
|
modules from .rs files and typically include metadata about the crate.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
~~~~ { .xfail-test }
|
2012-01-19 05:51:20 -06:00
|
|
|
|
#[link(name = "farm", vers = "2.5", author = "mjh")];
|
2012-04-05 18:26:36 -05:00
|
|
|
|
#[crate_type = "lib"];
|
2012-10-07 00:23:16 -05:00
|
|
|
|
|
2012-01-19 05:51:20 -06:00
|
|
|
|
mod cow;
|
|
|
|
|
mod chicken;
|
|
|
|
|
mod horse;
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
Compiling this file will cause `rustc` to look for files named
|
2012-10-07 00:23:16 -05:00
|
|
|
|
`cow.rs`, `chicken.rs`, and `horse.rs` in the same directory as the
|
|
|
|
|
`.rc` file, compile them all together, and, based on the presence of
|
|
|
|
|
the `crate_type = "lib"` attribute, output a shared library or an
|
|
|
|
|
executable. (If the line `#[crate_type = "lib"];` was omitted,
|
|
|
|
|
`rustc` would create an executable.)
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
The `#[link(...)]` attribute provides meta information about the
|
|
|
|
|
module, which other crates can use to load the right module. More
|
|
|
|
|
about that later.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
To have a nested directory structure for your source files, you can
|
|
|
|
|
nest mods in your `.rc` file:
|
|
|
|
|
|
2012-03-20 18:01:32 -05:00
|
|
|
|
~~~~ {.ignore}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
mod poultry {
|
|
|
|
|
mod chicken;
|
|
|
|
|
mod turkey;
|
|
|
|
|
}
|
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
The compiler will now look for `poultry/chicken.rs` and
|
|
|
|
|
`poultry/turkey.rs`, and export their content in `poultry::chicken`
|
|
|
|
|
and `poultry::turkey`. You can also provide a `poultry.rs` to add
|
|
|
|
|
content to the `poultry` module itself.
|
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
When compiling .rc files, if rustc finds a .rs file with the same
|
|
|
|
|
name, then that .rs file provides the top-level content of the crate.
|
2012-10-04 14:41:45 -05:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
~~~ {.xfail-test}
|
|
|
|
|
// foo.rc
|
|
|
|
|
#[link(name = "foo", vers="1.0")];
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
mod bar;
|
|
|
|
|
~~~
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
~~~ {.xfail-test}
|
|
|
|
|
// foo.rs
|
|
|
|
|
fn main() { bar::baz(); }
|
|
|
|
|
~~~
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
> ***Note***: The way rustc looks for .rs files to pair with .rc
|
|
|
|
|
> files is a major source of confusion and will change. It's likely
|
|
|
|
|
> that the crate and source file grammars will merge.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
> ***Note***: The way that directory modules are handled will also
|
|
|
|
|
> change. The code for directory modules currently lives in a .rs
|
|
|
|
|
> file with the same name as the directory, _next to_ the directory.
|
|
|
|
|
> A new scheme will make that file live _inside_ the directory.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
## Using other crates
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
The `extern mod` directive lets you use a crate (once it's been
|
|
|
|
|
compiled into a library) from inside another crate. `extern mod` can
|
|
|
|
|
appear at the top of a crate file or at the top of modules. It will
|
|
|
|
|
cause the compiler to look in the library search path (which you can
|
|
|
|
|
extend with the `-L` switch) for a compiled Rust library with the
|
|
|
|
|
right name, then add a module with that crate's name into the local
|
|
|
|
|
scope.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
For example, `extern mod std` links the [standard library].
|
|
|
|
|
|
|
|
|
|
[standard library]: std/index.html
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
When a comma-separated list of name/value pairs appears after `extern
|
|
|
|
|
mod`, the compiler front-end matches these pairs against the
|
|
|
|
|
attributes provided in the `link` attribute of the crate file. The
|
|
|
|
|
front-end will only select this crate for use if the actual pairs
|
|
|
|
|
match the declared attributes. You can provide a `name` value to
|
|
|
|
|
override the name used to search for the crate.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
Our example crate declared this set of `link` attributes:
|
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
~~~~ {.xfail-test}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
#[link(name = "farm", vers = "2.5", author = "mjh")];
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
Which you can then link with any (or all) of the following:
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
~~~~ {.xfail-test}
|
|
|
|
|
extern mod farm;
|
|
|
|
|
extern mod my_farm (name = "farm", vers = "2.5");
|
|
|
|
|
extern mod my_auxiliary_farm (name = "farm", author = "mjh");
|
|
|
|
|
~~~~
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
If any of the requested metadata do not match, then the crate
|
2012-10-07 00:23:16 -05:00
|
|
|
|
will not be compiled successfully.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
|
|
|
|
## A minimal example
|
|
|
|
|
|
|
|
|
|
Now for something that you can actually compile yourself. We have
|
|
|
|
|
these two files:
|
|
|
|
|
|
|
|
|
|
~~~~
|
2012-10-04 14:41:45 -05:00
|
|
|
|
// world.rs
|
|
|
|
|
#[link(name = "world", vers = "1.0")];
|
2012-10-12 18:41:16 -05:00
|
|
|
|
pub fn explore() -> &str { "world" }
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
~~~~ {.xfail-test}
|
2012-01-19 05:51:20 -06:00
|
|
|
|
// main.rs
|
2012-10-04 14:41:45 -05:00
|
|
|
|
extern mod world;
|
2012-10-12 18:41:16 -05:00
|
|
|
|
fn main() { io::println("hello " + world::explore()); }
|
2012-01-19 05:51:20 -06:00
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
|
|
Now compile and run like this (adjust to your platform if necessary):
|
|
|
|
|
|
2012-03-20 18:01:32 -05:00
|
|
|
|
~~~~ {.notrust}
|
2012-10-04 14:41:45 -05:00
|
|
|
|
> rustc --lib world.rs # compiles libworld-94839cbfe144198-1.0.so
|
|
|
|
|
> rustc main.rs -L . # compiles main
|
2012-01-19 05:51:20 -06:00
|
|
|
|
> ./main
|
|
|
|
|
"hello world"
|
|
|
|
|
~~~~
|
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
Notice that the library produced contains the version in the filename
|
|
|
|
|
as well as an inscrutable string of alphanumerics. These are both
|
|
|
|
|
part of Rust's library versioning scheme. The alphanumerics are
|
|
|
|
|
a hash representing the crate metadata.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
## The core library
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-10 23:29:25 -05:00
|
|
|
|
The Rust [core] library is the language runtime and contains
|
2012-10-07 00:23:16 -05:00
|
|
|
|
required memory management and task scheduling code as well as a
|
|
|
|
|
number of modules necessary for effective usage of the primitive
|
|
|
|
|
types. Methods on [vectors] and [strings], implementations of most
|
|
|
|
|
comparison and math operators, and pervasive types like [`Option`]
|
|
|
|
|
and [`Result`] live in core.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
All Rust programs link to the core library and import its contents,
|
|
|
|
|
as if the following were written at the top of the crate.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
~~~ {.xfail-test}
|
|
|
|
|
extern mod core;
|
|
|
|
|
use core::*;
|
|
|
|
|
~~~
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-10-07 00:23:16 -05:00
|
|
|
|
[core]: core/index.html
|
|
|
|
|
[vectors]: core/vec.html
|
|
|
|
|
[strings]: core/str.html
|
|
|
|
|
[`Option`]: core/option.html
|
|
|
|
|
[`Result`]: core/result.html
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 17:33:50 -05:00
|
|
|
|
# What next?
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 17:33:50 -05:00
|
|
|
|
Now that you know the essentials, check out any of the additional
|
|
|
|
|
tutorials on individual topics.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 17:33:50 -05:00
|
|
|
|
* [Borrowed pointers][borrow]
|
|
|
|
|
* [Tasks and communication][tasks]
|
|
|
|
|
* [Macros][macros]
|
|
|
|
|
* [The foreign function interface][ffi]
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 17:33:50 -05:00
|
|
|
|
There is further documentation on the [wiki], including articles about
|
|
|
|
|
[unit testing] in Rust, [documenting][rustdoc] and [packaging][cargo]
|
|
|
|
|
Rust code, and a discussion of the [attributes] used to apply metada
|
|
|
|
|
to code.
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 17:33:50 -05:00
|
|
|
|
[borrow]: tutorial-borrowed-ptr.html
|
|
|
|
|
[tasks]: tutorial-tasks.html
|
|
|
|
|
[macros]: tutorial-macros.html
|
|
|
|
|
[ffi]: tutorial-ffi.html
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 17:33:50 -05:00
|
|
|
|
[wiki]: https://github.com/mozilla/rust/wiki/Docs
|
|
|
|
|
[unit testing]: https://github.com/mozilla/rust/wiki/Doc-unit-testing
|
|
|
|
|
[rustdoc]: https://github.com/mozilla/rust/wiki/Doc-using-rustdoc
|
|
|
|
|
[cargo]: https://github.com/mozilla/rust/wiki/Doc-using-cargo-to-manage-packages
|
|
|
|
|
[attributes]: https://github.com/mozilla/rust/wiki/Doc-attributes
|
2012-01-19 05:51:20 -06:00
|
|
|
|
|
2012-09-22 17:33:50 -05:00
|
|
|
|
[pound-rust]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|