auto merge of #8777 : Kimundi/rust/doc_stuff, r=cmr

This commit is contained in:
bors 2013-08-27 06:45:50 -07:00
commit 4fa09e08ed

View File

@ -2251,80 +2251,141 @@ The full list of derivable traits is `Eq`, `TotalEq`, `Ord`,
`TotalOrd`, `Encodable` `Decodable`, `Clone`, `DeepClone`,
`IterBytes`, `Rand`, `Zero`, and `ToStr`.
# Modules and crates
# Crates and the module system
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.
Rust's module system is very powerful, but because of that also somewhat complex.
Nevertheless, this section will try to explain every important aspect of it.
## Crates
In order to speak about the module system, we first need to define the medium it exists in:
Let's say you've written a program or a library, compiled it, and got the resulting binary.
In Rust, the content of all source code that the compiler directly had to compile in order to end up with
that binary is collectively called a 'crate'.
For example, for a simple hello world program your crate only consists of this code:
~~~~
// main.rs
fn main() {
println("Hello world!");
}
~~~~
A crate is also the unit of independent compilation in Rust: `rustc` always compiles a single crate at a time,
from which it produces either a library or an executable.
Note that merely using an already compiled library in your code does not make it part of your crate.
## The module hierarchy
For every crate, all the code in it is arranged in a hierarchy of modules starting with a single
root module. That root module is called the 'crate root'.
All modules in a crate below the crate root are declared with the `mod` keyword:
~~~~
// This is the crate root
mod farm {
pub fn chicken() -> &str { "cluck cluck" }
pub fn cow() -> &str { "mooo" }
// This is the body of module 'farm' declared in the crate root.
fn chicken() { println("cluck cluck"); }
fn cow() { println("mooo"); }
mod barn {
// Body of module 'barn'
fn hay() { println("..."); }
}
}
fn main() {
println(farm::chicken());
println("Hello farm!");
}
~~~~
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.
As you can see, your module hierarchy is now three modules deep: There is the crate root, which contains your `main()`
function, and the module `farm`. The module `farm` also contains two functions and a third module `barn`,
which contains a function `hay`.
~~~
# mod farm { pub fn chicken() { } }
# fn main() {
// Bring `chicken` into scope
use farm::chicken;
(In case you already stumbled over `extern mod`: It isn't directly related to a bare `mod`, we'll get to it later. )
fn chicken_farmer() {
// The same, but name it `my_chicken`
use my_chicken = farm::chicken;
...
# my_chicken();
## Paths and visibility
We've now defined a nice module hierarchy. But how do we access the items in it from our `main` function?
One way to do it is to simply fully qualifying it:
~~~~ {.xfail-test}
mod farm {
fn chicken() { println("cluck cluck"); }
// ...
}
# chicken();
# }
~~~
These farm animal functions have a new keyword, `pub`, attached to
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 `static`, are module-private by default.
fn main() {
println("Hello chicken!");
::farm::chicken(); // Won't compile yet, see further down
}
~~~~
The `::farm::chicken` construct is what we call a 'path'.
Because it's starting with a `::`, it's also a 'global path',
which qualifies an item by its full path in the module hierarchy
relative to the crate root.
If the path were to start with a regular identifier, like `farm::chicken`, it would be
a 'local path' instead. We'll get to them later.
Now, if you actually tried to compile this code example, you'll notice
that you get a `unresolved name: 'farm::chicken'` error. That's because per default,
items (`fn`, `struct`, `static`, `mod`, ...) are only visible inside the module
they are defined in.
To make them visible outside their containing modules, you need to mark them _public_ with `pub`:
~~~~
mod farm {
pub fn chicken() { println("cluck cluck"); }
pub fn cow() { println("mooo"); }
// ...
}
fn main() {
println("Hello chicken!");
::farm::chicken(); // This compiles now
}
~~~~
Visibility restrictions in Rust exist only at module boundaries. This
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.
struct level.
For convenience, fields are _public_ by default, and can be made _private_ with the `priv` keyword:
~~~
pub mod farm {
mod farm {
# pub type Chicken = int;
# type Cow = int;
# struct Human(int);
# impl Human { fn rest(&self) { } }
# pub fn make_me_a_farm() -> Farm { Farm { chickens: ~[], cows: ~[], farmer: Human(0) } }
# pub fn make_me_a_farm() -> Farm { Farm { chickens: ~[], farmer: Human(0) } }
pub struct Farm {
priv chickens: ~[Chicken],
priv cows: ~[Cow],
farmer: Human
}
impl Farm {
fn feed_chickens(&self) { ... }
fn feed_cows(&self) { ... }
pub fn add_chicken(&self, c: Chicken) { ... }
}
pub fn feed_animals(farm: &Farm) {
farm.feed_chickens();
farm.feed_cows();
}
}
@ -2333,155 +2394,522 @@ fn main() {
f.add_chicken(make_me_a_chicken());
farm::feed_animals(&f);
f.farmer.rest();
// This wouldn't compile because both are private:
// f.feed_chickens();
// let chicken_counter = f.chickens.len();
}
# fn make_me_a_farm() -> farm::Farm { farm::make_me_a_farm() }
# fn make_me_a_chicken() -> farm::Chicken { 0 }
~~~
## Crates
> ***Note:*** Visibility rules are currently buggy and not fully defined, you might have to add or remove `pub` along a path until it works.
The unit of independent compilation in Rust is the crate: rustc
compiles a single crate at a time, from which it produces either a
library or an executable.
## Files and modules
When compiling a single `.rs` source 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.
One important aspect about Rusts module system is that source files are not important:
You define a module hierarchy, populate it with all your definitions, define visibility,
maybe put in a `fn main()`, and that's it: No need to think about source files.
Larger crates typically span multiple files and are, by convention,
compiled from a source file with the `.rc` extension, called a *crate file*.
The crate file extension distinguishes source files that represent
crates from those that do not, but otherwise source files and crate files are identical.
The only file that's relevant is the one that contains the body of your crate root,
and it's only relevant because you have to pass that file to `rustc` to compile your crate.
A typical crate file declares attributes associated with the crate that
may affect how the compiler processes the source.
Crate attributes specify metadata used for locating and linking crates,
the type of crate (library or executable),
and control warning and error behavior,
among other things.
Crate files additionally declare the external crates they depend on
as well as any modules loaded from other files.
And in principle, that's all you need: You can write any Rust program as one giant source file that contains your
crate root and everything below it in `mod ... { ... }` declarations.
However, in practice you usually want to split you code up into multiple source files to make it more manageable.
In order to do that, Rust allows you to move the body of any module into it's own source file, which works like this:
If you declare a module without its body, like `mod foo;`, the compiler will look for the
files `foo.rs` and `foo/mod.rs`. If it finds either, it uses the content of that file as the body of the module.
If it finds both, that's a compile error.
So, if we want to move the content of `mod farm` into it's own file, it would look like this:
~~~~ {.ignore}
// main.rs - contains body of the crate root
mod farm; // Compiler will look for 'farm.rs' and 'farm/mod.rs'
fn main() {
println("Hello farm!");
::farm::cow();
}
~~~~
~~~~
// farm.rs - contains body of module 'farm' in the crate root
pub fn chicken() { println("cluck cluck"); }
pub fn cow() { println("mooo"); }
pub mod barn {
pub fn hay() { println("..."); }
}
# fn main() { }
~~~~
So, in short `mod foo;` is just syntactic sugar for `mod foo { /* include content of foo.rs or foo/mod.rs here */ }`.
This also means that having two or more identical `mod foo;` somewhere
in your crate hierarchy is generally a bad idea,
just like copy-and-paste-ing a module into two or more places is one.
Both will result in duplicate and mutually incompatible definitions.
The directory the compiler looks in for those two files is determined by starting with
the same directory as the source file that contains the `mod foo;` declaration, and concatenating to that a
path equivalent to the relative path of all nested `mod { ... }` declarations the `mod foo;` is contained in, if any.
For example, given a file with this module body:
~~~ {.ignore}
// src/main.rs
mod plants;
mod fungi;
mod animals {
mod fish;
mod mammals {
mod humans;
}
}
~~~
The compiler would then try all these files:
~~~ {.notrust}
src/plants.rs
src/plants/mod.rs
src/fungi.rs
src/fungi/mod.rs
src/animals/fish.rs
src/animals/fish/mod.rs
src/animals/mammals/humans.rs
src/animals/mammals/humans/mod.rs
~~~
These rules per default result in any directory structure mirroring
the crates's module hierarchy, and allow you to have both small modules that only need
to consist of one source file, and big modules that group the source files of submodules together.
If you need to circumvent those defaults, you can also overwrite the path a `mod foo;` would take:
~~~ {.ignore}
#[path="../../area51/classified.rs"]
mod alien;
~~~
## Importing names into the local scope
Always referring to definitions in other modules with their global
path gets old really fast, so Rust has a way to import
them into the local scope of your module: `use`-statements.
They work like this: At the beginning of any module body, `fn` body, or any other block
you can write a list of `use`-statements, consisting of the keyword `use` and a __global path__ to an item
without the `::` prefix. For example, this imports `cow` into the local scope:
~~~
use farm::cow;
# mod farm { pub fn cow() { println("I'm a hidden ninja cow!") } }
# fn main() { cow() }
~~~
The path you give to `use` is per default global, meaning relative to the crate root,
no matter how deep the module hierarchy is, or whether the module body it's written in
is contained in its own file (remember: files are irrelevant).
This is different to other languages, where you often only find a single import construct that combines the semantic
of `mod foo;` and `use`-statements, and which tend to work relative to the source file or use an absolute file path
- Rubys `require` or C/C++'s `#include` come to mind.
However, it's also possible to import things relative to the module of the `use`-statement:
Adding a `super::` in front of the path will start in the parent module,
while adding a `self::` prefix will start in the current module:
~~~
# mod workaround {
# pub fn some_parent_item(){ println("...") }
# mod foo {
use super::some_parent_item;
use self::some_child_module::some_item;
# pub fn bar() { some_parent_item(); some_item() }
# pub mod some_child_module { pub fn some_item() {} }
# }
# }
~~~
Again - relative to the module, not to the file.
Imports are also shadowed by local definitions:
For each name you mention in a module/block, `rust`
will first look at all items that are defined locally,
and only if that results in no match look at items you brought in
scope with corresponding `use` statements.
~~~ {.ignore}
# // XXX: Allow unused import in doc test
use farm::cow;
// ...
# mod farm { pub fn cow() { println("Hidden ninja cow is hidden.") } }
fn cow() { println("Mooo!") }
fn main() {
cow() // resolves to the locally defined cow() function
}
~~~
To make this behavior more obvious, the rule has been made that `use`-statement always need to be written
before any declaration, like in the example above. This is a purely artificial rule introduced
because people always assumed they shadowed each other based on order, despite the fact that all items in rust are
mutually recursive, order independent definitions.
One odd consequence of that rule is that `use` statements also go in front of any `mod` declaration,
even if they refer to things inside them:
~~~
use farm::cow;
mod farm {
pub fn cow() { println("Moooooo?") }
}
fn main() { cow() }
~~~
This is what our `farm` example looks like with `use` statements:
~~~~
use farm::chicken;
use farm::cow;
use farm::barn;
mod farm {
pub fn chicken() { println("cluck cluck"); }
pub fn cow() { println("mooo"); }
pub mod barn {
pub fn hay() { println("..."); }
}
}
fn main() {
println("Hello farm!");
// Can now refer to those names directly:
chicken();
cow();
barn::hay();
}
~~~~
And here an example with multiple files:
~~~{.ignore}
// a.rs - crate root
use b::foo;
mod b;
fn main() { foo(); }
~~~
~~~{.ignore}
// b.rs
use b::c::bar;
pub mod c;
pub fn foo() { bar(); }
~~~
~~~
// c.rs
pub fn bar() { println("Baz!"); }
~~~
There also exist two short forms for importing multiple names at once:
1. Explicit mention multiple names as the last element of an `use` path:
~~~
use farm::{chicken, cow};
# mod farm {
# pub fn cow() { println("Did I already mention how hidden and ninja I am?") }
# pub fn chicken() { println("I'm Bat-chicken, guardian of the hidden tutorial code.") }
# }
# fn main() { cow(); chicken() }
~~~
2. Import everything in a module with a wildcard:
~~~
use farm::*;
# mod farm {
# pub fn cow() { println("Bat-chicken? What a stupid name!") }
# pub fn chicken() { println("Says the 'hidden ninja' cow.") }
# }
# fn main() { cow(); chicken() }
~~~
However, that's not all. You can also rename an item while you're bringing it into scope:
~~~
use egg_layer = farm::chicken;
# mod farm { pub fn chicken() { println("Laying eggs is fun!") } }
// ...
fn main() {
egg_layer();
}
~~~
In general, `use` creates an local alias:
An alternate path and a possibly different name to access the same item,
whiteout touching the original, and with both being interchangeable.
## Reexporting names
It is also possible to reexport items to be accessible under your module.
For that, you write `pub use`:
~~~
mod farm {
pub use self::barn::hay;
pub fn chicken() { println("cluck cluck"); }
pub fn cow() { println("mooo"); }
mod barn {
pub fn hay() { println("..."); }
}
}
fn main() {
farm::chicken();
farm::cow();
farm::hay();
}
~~~
Just like in normal `use` statements, the exported names
merely represent an alias to the same thing and can also be renamed.
The above example also demonstrate what you can use `pub use` for:
The nested `barn` module is private, but the `pub use` allows users
of the module `farm` to access a function from `barn` without needing
to know that `barn` exists.
In other words, you can use them to decouple an public api from their internal implementation.
## Using libraries
So far we've only talked about how to define and structure your own crate.
However, most code out there will want to use preexisting libraries,
as there really is no reason to start from scratch each time you start a new project.
In Rust terminology, we need a way to refer to other crates.
For that, Rust offers you the `extern mod` declaration:
~~~
extern mod extra;
// extra ships with Rust, you'll find more details further down.
fn main() {
// The rational number '1/2':
let one_half = ::extra::rational::Ratio::new(1, 2);
}
~~~
Despite its name, `extern mod` is a distinct construct from regular `mod` declarations:
A statement of the form `extern mod foo;` will cause `rustc` to search for the crate `foo`,
and if it finds a matching binary it lets you use it from inside your crate.
The effect it has on your module hierarchy mirrors aspects of both `mod` and `use`:
- Like `mod`, it causes `rustc` to actually emit code:
The linkage information the binary needs to use the library `foo`.
- But like `use`, all `extern mod` statements that refer to the same library are interchangeable,
as each one really just presents an alias to an external module (the crate root of the library your linking against).
Remember how `use`-statements have to go before local declarations because the latter shadows the former?
Well, `extern mod` statements also have their own rules in that regard:
Both `use` and local declarations can shadow them, so the rule is that `extern mod` has to go in front
of both `use` and local declarations.
Which can result in something like this:
~~~
extern mod extra;
use farm::dog;
use extra::rational::Ratio;
mod farm {
pub fn dog() { println("woof"); }
}
fn main() {
farm::dog();
let a_third = Ratio::new(1, 3);
}
~~~
It's a bit weird, but it's the result of shadowing rules that have been set that way because
they model most closely what people expect to shadow.
## Package ids
If you use `extern mod`, per default `rustc` will look for libraries in the the library search path (which you can
extend with the `-L` switch).
However, Rust also ships with rustpkg, a package manager that is able to automatically download and build
libraries if you use it for building your crate. How it works is explained [here][rustpkg],
but for this tutorial it's only important to know that you can optionally annotate an
`extern mod` statement with an package id that rustpkg can use to identify it:
~~~ {.ignore}
extern mod rust = "github.com/mozilla/rust"; // pretend Rust is an simple library
~~~
[rustpkg]: rustpkg.html
## Crate metadata and settings
For every crate you can define a number of metadata items, such as link name, version or author.
You can also toggle settings that have crate-global consequences. Both mechanism
work by providing attributes in the crate root.
For example, Rust uniquely identifies crates by their link metadate, which includes
the link name and the version. It also hashes the filename and the symbols in a binary
based on the link metadata, allowing you to use two different versions of the same library in a crate
without conflict.
Therefor, if you plan to compile your crate as a library, you should annotate it with that information:
~~~~
// lib.rs
# #[crate_type = "lib"];
// Crate linkage metadata
#[link(name = "farm", vers = "2.5")];
// ...
# pub fn farm() {}
~~~~
You can also in turn require in a `extern mod` statement that certain link metadata items match some criteria.
For that, Rust currently parses a comma-separated list of name/value pairs that appear after
it, and ensures that they match the attributes provided in the `link` attribute of a crate file.
This enables you to, eg, pick a a crate based on it's version number, or to link an library under an
different name. For example, this two mod statements would both accept and select the crate define above:
~~~~ {.xfail-test}
// Crate linkage metadata
#[link(name = "farm", vers = "2.5", author = "mjh")];
extern mod farm(vers = "2.5");
extern mod my_farm(name = "farm", vers = "2.5");
~~~~
// Make a library ("bin" is the default)
Other crate settings and metadata include things like enabling/disabling certain errors or warnings,
or setting the crate type (library or executable) explicitly:
~~~~
// lib.rs
// ...
// This crate is a library ("bin" is the default)
#[crate_type = "lib"];
// Turn on a warning
#[warn(non_camel_case_types)]
// Link to the standard library
extern mod std;
// Load some modules from other files
mod cow;
mod chicken;
mod horse;
fn main() {
...
}
# pub fn farm() {}
~~~~
Compiling this file will cause `rustc` to look for files named
`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.)
If you're compiling your crate with `rustpkg`,
link annotations will not be necessary, because they get
inferred by `rustpkg` based on the Package id and naming conventions.
The `#[link(...)]` attribute provides meta information about the
module, which other crates can use to load the right module. More
about that later.
To have a nested directory structure for your source files, you can
nest mods:
~~~~ {.ignore}
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.
## Using other crates
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.
For example, `extern mod std` links the [standard library].
[standard library]: std/index.html
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.
Our example crate declared this set of `link` attributes:
~~~~
#[link(name = "farm", vers = "2.5", author = "mjh")];
~~~~
Which you can then link with any (or all) of the following:
~~~~ {.xfail-test}
extern mod farm;
extern mod my_farm (name = "farm", vers = "2.5");
extern mod my_auxiliary_farm (name = "farm", author = "mjh");
~~~~
If any of the requested metadata do not match, then the crate
will not be compiled successfully.
> ***Note:*** The rules regarding link metadata, both as attributes and on `extern mod`,
as well as their interaction with `rustpkg`
are currently not clearly defined and will likely change in the future.
## A minimal example
Now for something that you can actually compile yourself, we have
these two files:
Now for something that you can actually compile yourself.
We define two crates, and use one of them as a library in the other.
~~~~
// world.rs
#[link(name = "world", vers = "1.0")];
pub fn explore() -> &str { "world" }
#[link(name = "world", vers = "0.42")];
pub fn explore() -> &'static str { "world" }
~~~~
~~~~ {.xfail-test}
// main.rs
extern mod world;
fn main() { println(~"hello " + world::explore()); }
fn main() { println("hello " + world::explore()); }
~~~~
Now compile and run like this (adjust to your platform if necessary):
~~~~ {.notrust}
> rustc --lib world.rs # compiles libworld-94839cbfe144198-1.0.so
> rustc --lib world.rs # compiles libworld-<HASH>-0.42.so
> rustc main.rs -L . # compiles main
> ./main
"hello world"
~~~~
Notice that the library produced contains the version in the file name
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.
as well as an inscrutable string of alphanumerics. As explained in the previous paragraph,
these are both part of Rust's library versioning scheme. The alphanumerics are
a hash representing the crates link metadata.
## The standard library
## The standard library and the prelude
While reading the examples in this tutorial, you might have asked yourself where all
those magical predefined items like `println()` are coming from.
The truth is, there's nothing magical about them: They are all defined normally
in the `std` library, which is a crate that ships with Rust.
The only magical thing that happens is that `rustc` automatically inserts this line into your crate root:
~~~ {.ignore}
extern mod std;
~~~
As well as this line into every module body:
~~~ {.ignore}
use std::prelude::*;
~~~
The role of the `prelude` module is to re-exports common definitions from `std`.
This allows you to use common types and functions like `Option<T>` or `println`
without needing to import them. And if you need something from `std` that's not in the prelude,
you just have to import it with an `use` statement.
For example, it re-exports `println` which is defined in `std::io::println`:
~~~
use puts = std::io::println;
fn main() {
println("println is imported per default.");
puts("Doesn't hinder you from importing it under an different name yourself.");
::std::io::println("Or from not using the automatic import.");
}
~~~
Both auto-insertions can be disabled with an attribute if necessary:
~~~
// In the crate root:
#[no_std];
~~~
~~~
// In any module:
#[no_implicit_prelude];
~~~
## The standard library in detail
The Rust standard library provides runtime features required by the language,
including the task scheduler and memory allocators, as well as library
@ -2499,24 +2927,9 @@ I/O abstractions ([`io`]), [containers] like [`hashmap`],
common traits ([`kinds`], [`ops`], [`cmp`], [`num`],
[`to_str`], [`clone`]), and complete bindings to the C standard library ([`libc`]).
### Standard Library injection and the Rust prelude
`std` is imported at the topmost level of every crate by default, as
if the first line of each crate was
extern mod std;
This means that the contents of std can be accessed from from any context
with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`,
etc.
Additionally, `std` contains a `prelude` module that reexports many of the
most common standard modules, types and traits. The contents of the prelude are
imported into every *module* by default. Implicitly, all modules behave as if
they contained the following prologue:
use std::prelude::*;
The full documentation for `std` can be found here: [standard library].
[standard library]: std/index.html
[`std`]: std/index.html
[`bool`]: std/bool.html
[tuples]: std/tuple.html
@ -2543,6 +2956,18 @@ they contained the following prologue:
[`clone`]: std/clone.html
[`libc`]: std/libc.html
## The extra library
Rust also ships with the [extra library], an accumulation of
useful things, that are however not important enough
to deserve a place in the standard library.
You can use them by linking to `extra` with an `extern mod extra;`.
[extra library]: extra/index.html
Right now `extra` contains those definitions directly, but in the future it will likely just
re-export a bunch of 'officially blessed' crates that get managed with `rustpkg`.
# What next?
Now that you know the essentials, check out any of the additional
@ -2555,7 +2980,7 @@ tutorials on individual topics.
* [Containers and iterators](tutorial-container.html)
* [Error-handling and Conditions](tutorial-conditions.html)
There is further documentation on the [wiki].
There is further documentation on the [wiki], however those tend to be even more out of date as this document.
[borrow]: tutorial-borrowed-ptr.html
[tasks]: tutorial-tasks.html