This adds strictly more information to the source files and reduces the
need for customized tooling to render the book.
(While this should not change the output of _rustbook_, it is very
useful when rendering the sources with external tools like Pandoc.)
21 files changed:
can have both an `&[T]` or a `&mut [T]`. If we wanted to accept both of these
types, `Borrow` is up for it:
can have both an `&[T]` or a `&mut [T]`. If we wanted to accept both of these
types, `Borrow` is up for it:
use std::borrow::Borrow;
use std::fmt::Display;
use std::borrow::Borrow;
use std::fmt::Display;
pattern. The unstable `box` keyword can be used to both create and destructure
a `Box`. An example usage would be:
pattern. The unstable `box` keyword can be used to both create and destructure
a `Box`. An example usage would be:
#![feature(box_syntax, box_patterns)]
fn main() {
#![feature(box_syntax, box_patterns)]
fn main() {
Rust's standard library provides a library for threads, which allow you to
run Rust code in parallel. Here's a basic example of using `std::thread`:
Rust's standard library provides a library for threads, which allow you to
run Rust code in parallel. Here's a basic example of using `std::thread`:
use std::thread;
fn main() {
use std::thread;
fn main() {
new thread. It returns a handle to the thread, that can be used to
wait for the child thread to finish and extract its result:
new thread. It returns a handle to the thread, that can be used to
wait for the child thread to finish and extract its result:
use std::thread;
fn main() {
use std::thread;
fn main() {
We can use `Arc<T>` to fix this. Here's the working version:
We can use `Arc<T>` to fix this. Here's the working version:
use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::{Arc, Mutex};
use std::thread;
Here's a version of our code that uses channels for synchronization, rather
than waiting for a specific time:
Here's a version of our code that uses channels for synchronization, rather
than waiting for a specific time:
use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc;
While this channel is just sending a generic signal, we can send any data that
is `Send` over the channel!
While this channel is just sending a generic signal, we can send any data that
is `Send` over the channel!
use std::thread;
use std::sync::mpsc;
use std::thread;
use std::sync::mpsc;
A `panic!` will crash the currently executing thread. You can use Rust's
threads as a simple isolation mechanism:
A `panic!` will crash the currently executing thread. You can use Rust's
threads as a simple isolation mechanism:
use std::thread;
let result = thread::spawn(move || {
use std::thread;
let result = thread::spawn(move || {
To define each of our modules, we use the `mod` keyword. Let’s make our
`src/lib.rs` look like this:
To define each of our modules, we use the `mod` keyword. Let’s make our
`src/lib.rs` look like this:
mod english {
mod greetings {
}
mod english {
mod greetings {
}
Rust keeps track of these comments, and uses them when generating
documentation. This is important when documenting things like enums:
Rust keeps track of these comments, and uses them when generating
documentation. This is important when documenting things like enums:
/// The `Option` type. See [the module level documentation](../) for more.
enum Option<T> {
/// No value
/// The `Option` type. See [the module level documentation](../) for more.
enum Option<T> {
/// No value
Anyway, let's cover each part of this comment in detail:
Anyway, let's cover each part of this comment in detail:
/// Constructs a new `Rc<T>`.
# fn foo() {}
```
/// Constructs a new `Rc<T>`.
# fn foo() {}
```
The first line of a documentation comment should be a short summary of its
functionality. One sentence. Just the basics. High level.
The first line of a documentation comment should be a short summary of its
functionality. One sentence. Just the basics. High level.
///
/// Other details about constructing `Rc<T>`s, maybe describing complicated
/// semantics, maybe additional options, all kinds of stuff.
///
/// Other details about constructing `Rc<T>`s, maybe describing complicated
/// semantics, maybe additional options, all kinds of stuff.
/// # Examples
# fn foo() {}
```
/// # Examples
# fn foo() {}
```
are three kinds of headers that are commonly used. They aren't special syntax,
just convention, for now.
are three kinds of headers that are commonly used. They aren't special syntax,
just convention, for now.
/// # Panics
# fn foo() {}
```
/// # Panics
# fn foo() {}
```
least. If your function has a non-trivial contract like this, that is
detected/enforced by panics, documenting it is very important.
least. If your function has a non-trivial contract like this, that is
detected/enforced by panics, documenting it is very important.
/// # Failures
# fn foo() {}
```
/// # Failures
# fn foo() {}
```
slightly less important than `Panics`, because failure is encoded into the type
system, but it's still a good thing to do.
slightly less important than `Panics`, because failure is encoded into the type
system, but it's still a good thing to do.
/// # Safety
# fn foo() {}
```
/// # Safety
# fn foo() {}
```
If your function is `unsafe`, you should explain which invariants the caller is
responsible for upholding.
If your function is `unsafe`, you should explain which invariants the caller is
responsible for upholding.
/// # Examples
///
/// ```
/// # Examples
///
/// ```
code block annotations, which we'll talk about in a moment, and can have
more than one section:
code block annotations, which we'll talk about in a moment, and can have
more than one section:
/// # Examples
///
/// Simple `&str` patterns:
/// # Examples
///
/// Simple `&str` patterns:
To write some Rust code in a comment, use the triple graves:
To write some Rust code in a comment, use the triple graves:
/// ```
/// println!("Hello, world");
/// ```
/// ```
/// println!("Hello, world");
/// ```
If you want something that's not Rust code, you can add an annotation:
If you want something that's not Rust code, you can add an annotation:
/// ```c
/// printf("Hello, world\n");
/// ```
/// ```c
/// printf("Hello, world\n");
/// ```
Let's discuss our sample example documentation:
Let's discuss our sample example documentation:
/// ```
/// println!("Hello, world");
/// ```
/// ```
/// println!("Hello, world");
/// ```
automatically add a main() wrapper around your code, and in the right place.
For example:
automatically add a main() wrapper around your code, and in the right place.
For example:
/// ```
/// use std::rc::Rc;
///
/// ```
/// use std::rc::Rc;
///
This will end up testing:
This will end up testing:
fn main() {
use std::rc::Rc;
let five = Rc::new(5);
fn main() {
use std::rc::Rc;
let five = Rc::new(5);
looks different than the output:
looks different than the output:
/// Some documentation.
# fn foo() {}
```
/// Some documentation.
# fn foo() {}
```
longer examples in detail, while still preserving the testability of your
documentation. For example, this code:
longer examples in detail, while still preserving the testability of your
documentation. For example, this code:
let x = 5;
let y = 6;
println!("{}", x + y);
let x = 5;
let y = 6;
println!("{}", x + y);
First, we set `x` to five:
First, we set `x` to five:
let x = 5;
# let y = 6;
# println!("{}", x + y);
let x = 5;
# let y = 6;
# println!("{}", x + y);
# let x = 5;
let y = 6;
# println!("{}", x + y);
# let x = 5;
let y = 6;
# println!("{}", x + y);
Finally, we print the sum of `x` and `y`:
Finally, we print the sum of `x` and `y`:
# let x = 5;
# let y = 6;
println!("{}", x + y);
# let x = 5;
# let y = 6;
println!("{}", x + y);
Here’s an example of documenting a macro:
Here’s an example of documenting a macro:
/// Panic with a given message unless an expression evaluates to true.
///
/// # Examples
/// Panic with a given message unless an expression evaluates to true.
///
/// # Examples
There are a few more annotations that are useful to help `rustdoc` do the right
thing when testing your code:
There are a few more annotations that are useful to help `rustdoc` do the right
thing when testing your code:
/// ```ignore
/// fn foo() {
/// ```
/// ```ignore
/// fn foo() {
/// ```
with `text` if it's not code, or using `#`s to get a working example that
only shows the part you care about.
with `text` if it's not code, or using `#`s to get a working example that
only shows the part you care about.
/// ```should_panic
/// assert!(false);
/// ```
/// ```should_panic
/// assert!(false);
/// ```
`should_panic` tells `rustdoc` that the code should compile correctly, but
not actually pass as a test.
`should_panic` tells `rustdoc` that the code should compile correctly, but
not actually pass as a test.
/// ```no_run
/// loop {
/// println!("Hello, world");
/// ```no_run
/// loop {
/// println!("Hello, world");
Rust has another kind of doc comment, `//!`. This comment doesn't document the next item, but the enclosing item. In other words:
Rust has another kind of doc comment, `//!`. This comment doesn't document the next item, but the enclosing item. In other words:
mod foo {
//! This is documentation for the `foo` module.
//!
mod foo {
//! This is documentation for the `foo` module.
//!
This is where you'll see `//!` used most often: for module documentation. If
you have a module in `foo.rs`, you'll often open its code and see this:
This is where you'll see `//!` used most often: for module documentation. If
you have a module in `foo.rs`, you'll often open its code and see this:
//! A module for using `foo`s.
//!
//! The `foo` module contains a lot of useful functionality blah blah blah
//! A module for using `foo`s.
//!
//! The `foo` module contains a lot of useful functionality blah blah blah
When you write documentation in Markdown files, you don't need to prefix
the documentation with comments. For example:
When you write documentation in Markdown files, you don't need to prefix
the documentation with comments. For example:
/// # Examples
///
/// ```
/// # Examples
///
/// ```
At a deeper level, documentation comments are sugar for documentation attributes:
At a deeper level, documentation comments are sugar for documentation attributes:
are the same, as are these:
are the same, as are these:
//! this
#![doc="/// this"]
//! this
#![doc="/// this"]
You can control a few aspects of the HTML that `rustdoc` generates through the
`#![doc]` version of the attribute:
You can control a few aspects of the HTML that `rustdoc` generates through the
`#![doc]` version of the attribute:
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")];
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")];
length is number of elements currently contained, and the capacity is the total size in elements of
the allocated memory. The length is less than or equal to the capacity.
length is number of elements currently contained, and the capacity is the total size in elements of
the allocated memory. The length is less than or equal to the capacity.
# #![feature(libc)]
# extern crate libc;
# use libc::{c_int, size_t};
# #![feature(libc)]
# extern crate libc;
# use libc::{c_int, size_t};
`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
the true length after compression for setting the length.
`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
the true length after compression for setting the length.
# #![feature(libc)]
# extern crate libc;
# use libc::{size_t, c_int};
# #![feature(libc)]
# extern crate libc;
# use libc::{size_t, c_int};
Decompression is similar, because snappy stores the uncompressed size as part of the compression
format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
Decompression is similar, because snappy stores the uncompressed size as part of the compression
format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
# #![feature(libc)]
# extern crate libc;
# use libc::{size_t, c_int};
# #![feature(libc)]
# extern crate libc;
# use libc::{size_t, c_int};
Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
this:
Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
this:
unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr }
```
unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr }
```
calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
conventions. Rust provides a way to tell the compiler which convention to use:
calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
conventions. Rust provides a way to tell the compiler which convention to use:
# #![feature(libc)]
extern crate libc;
# #![feature(libc)]
extern crate libc;
You may wish to compile Rust code in a way so that it can be called from C. This is
fairly easy, but requires a few things:
You may wish to compile Rust code in a way so that it can be called from C. This is
fairly easy, but requires a few things:
#[no_mangle]
pub extern fn hello_rust() -> *const u8 {
"Hello, world!\0".as_ptr()
#[no_mangle]
pub extern fn hello_rust() -> *const u8 {
"Hello, world!\0".as_ptr()
languages where an assignment evaluates to the assigned value (e.g. `5` in the
previous example), in Rust the value of an assignment is an empty tuple `()`:
languages where an assignment evaluates to the assigned value (e.g. `5` in the
previous example), in Rust the value of an assignment is an empty tuple `()`:
let mut y = 5;
let x = (y = 6); // x has the value `()`, not `6`
let mut y = 5;
let x = (y = 6); // x has the value `()`, not `6`
Rust has some special syntax for ‘diverging functions’, which are functions that
do not return:
Rust has some special syntax for ‘diverging functions’, which are functions that
do not return:
fn diverges() -> ! {
panic!("This function never returns!");
}
fn diverges() -> ! {
panic!("This function never returns!");
}
You can store a generic type in a `struct` as well:
You can store a generic type in a `struct` as well:
struct Point<T> {
x: T,
y: T,
struct Point<T> {
x: T,
y: T,
‘[pattern][patterns]’. We’ll use patterns more later. It’s easy enough
to use for now:
‘[pattern][patterns]’. We’ll use patterns more later. It’s easy enough
to use for now:
let foo = 5; // immutable.
let mut bar = 5; // mutable
```
let foo = 5; // immutable.
let mut bar = 5; // mutable
```
The `assembly template` is the only required parameter and must be a
literal string (i.e. `""`)
The `assembly template` is the only required parameter and must be a
literal string (i.e. `""`)
#![feature(asm)]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#![feature(asm)]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Output operands, input operands, clobbers and options are all optional
but you must add the right number of `:` if you skip them:
Output operands, input operands, clobbers and options are all optional
but you must add the right number of `:` if you skip them:
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
Whitespace also doesn't matter:
Whitespace also doesn't matter:
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
expressions must be mutable lvalues, or not yet assigned:
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
expressions must be mutable lvalues, or not yet assigned:
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn add(a: i32, b: i32) -> i32 {
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn add(a: i32, b: i32) -> i32 {
operand. This is useful for very low level programming, where
which register you use is important:
operand. This is useful for very low level programming, where
which register you use is important:
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# unsafe fn read_byte_in(port: u16) -> u8 {
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# unsafe fn read_byte_in(port: u16) -> u8 {
compiler not to assume any values loaded into those registers will
stay valid.
compiler not to assume any values loaded into those registers will
stay valid.
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
the compiler to insert its usual stack alignment code
3. *intel* - use intel syntax instead of the default AT&T.
the compiler to insert its usual stack alignment code
3. *intel* - use intel syntax instead of the default AT&T.
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() {
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() {
perform efficient pointer arithmetic, one would import those functions
via a declaration like
perform efficient pointer arithmetic, one would import those functions
via a declaration like
# #![feature(intrinsics)]
# fn main() {}
# #![feature(intrinsics)]
# fn main() {}
and one for deallocation. A freestanding program that uses the `Box`
sugar for dynamic allocations via `malloc` and `free`:
and one for deallocation. A freestanding program that uses the `Box`
sugar for dynamic allocations via `malloc` and `free`:
#![feature(lang_items, box_syntax, start, no_std, libc)]
#![no_std]
#![feature(lang_items, box_syntax, start, no_std, libc)]
#![no_std]
assert!(5 < 3);
assert_eq!(5, 3);
```
assert!(5 < 3);
assert_eq!(5, 3);
```
## try!
`try!` is used for error handling. It takes something that can return a
## try!
`try!` is used for error handling. It takes something that can return a
original example, `foo.bar().baz()`? This is called ‘method chaining’, and we
can do it by returning `self`.
original example, `foo.bar().baz()`? This is called ‘method chaining’, and we
can do it by returning `self`.
struct Circle {
x: f64,
y: f64,
struct Circle {
x: f64,
y: f64,
# struct Circle;
# impl Circle {
fn grow(&self) -> Circle {
# struct Circle;
# impl Circle {
fn grow(&self) -> Circle {
have method overloading, named arguments, or variable arguments. We employ
the builder pattern instead. It looks like this:
have method overloading, named arguments, or variable arguments. We employ
the builder pattern instead. It looks like this:
struct Circle {
x: f64,
y: f64,
struct Circle {
x: f64,
y: f64,
However, by using `Cell<T>`, you can emulate field-level mutability:
However, by using `Cell<T>`, you can emulate field-level mutability:
use std::cell::Cell;
struct Point {
use std::cell::Cell;
struct Point {
The function marked `#[start]` is passed the command line parameters
in the same format as C:
The function marked `#[start]` is passed the command line parameters
in the same format as C:
#![feature(lang_items, start, no_std, libc)]
#![no_std]
#![feature(lang_items, start, no_std, libc)]
#![no_std]
You can disambiguate a single-element tuple from a value in parentheses with a
comma:
You can disambiguate a single-element tuple from a value in parentheses with a
comma:
(0,); // single-element tuple
(0); // zero in parentheses
```
(0,); // single-element tuple
(0); // zero in parentheses
```
Functions also have a type! They look like this:
Functions also have a type! They look like this:
fn foo(x: i32) -> i32 { x }
let x: fn(i32) -> i32 = foo;
fn foo(x: i32) -> i32 { x }
let x: fn(i32) -> i32 = foo;
`String`s will coerce into `&str` with an `&`:
`String`s will coerce into `&str` with an `&`:
fn takes_slice(slice: &str) {
println!("Got: {}", slice);
}
fn takes_slice(slice: &str) {
println!("Got: {}", slice);
}
make sure that the failure message contains the provided text. A safer version
of the example above would be:
make sure that the failure message contains the provided text. A safer version
of the example above would be:
#[test]
#[should_panic(expected = "assertion failed")]
fn it_works() {
#[test]
#[should_panic(expected = "assertion failed")]
fn it_works() {
bounds isn’t too bad, but as the number increases, the syntax gets increasingly
awkward:
bounds isn’t too bad, but as the number increases, the syntax gets increasingly
awkward:
use std::fmt::Debug;
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
use std::fmt::Debug;
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
Rust has a solution, and it’s called a ‘`where` clause’:
Rust has a solution, and it’s called a ‘`where` clause’:
use std::fmt::Debug;
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
use std::fmt::Debug;
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
and then add `where` after the parameter list. For longer lists, whitespace can
be added:
and then add `where` after the parameter list. For longer lists, whitespace can
be added:
use std::fmt::Debug;
fn bar<T, K>(x: T, y: K)
use std::fmt::Debug;
fn bar<T, K>(x: T, y: K)
`where` is also more powerful than the simpler syntax. For example:
`where` is also more powerful than the simpler syntax. For example:
trait ConvertTo<Output> {
fn convert(&self) -> Output;
}
trait ConvertTo<Output> {
fn convert(&self) -> Output;
}
There’s an alternate form of `vec!` for repeating an initial value:
There’s an alternate form of `vec!` for repeating an initial value:
let v = vec![0; 10]; // ten zeroes
```
let v = vec![0; 10]; // ten zeroes
```