tutorial: More intro simplification
This commit is contained in:
parent
c2bc5122cd
commit
0cabd6fa1a
289
doc/tutorial.md
289
doc/tutorial.md
@ -61,41 +61,41 @@ they don't contain references to things that aren't actually defined.
|
|||||||
|
|
||||||
# Getting started
|
# Getting started
|
||||||
|
|
||||||
## Installation
|
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.
|
||||||
|
|
||||||
The Rust compiler currently must be built from a [tarball][]. We hope
|
Since the Rust compiler is written in Rust, it must be built by
|
||||||
to be distributing binary packages for various operating systems in
|
a precompiled "snapshot" version of itself (made in an earlier state
|
||||||
the future.
|
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.
|
||||||
|
|
||||||
The Rust compiler is slightly unusual in that it is written in Rust
|
Snapshot binaries are currently built and tested on several platforms:
|
||||||
and therefore must be built by a precompiled "snapshot" version of
|
|
||||||
itself (made in an earlier state of development). As such, source
|
|
||||||
builds require that:
|
|
||||||
|
|
||||||
* You are connected to the internet, to fetch snapshots.
|
* Windows (7, Server 2008 R2), x86 only
|
||||||
* You can at least execute snapshot binaries of one of the forms we
|
* Linux (various distributions), x86 and x86-64
|
||||||
offer them in. Currently we build and test snapshots on:
|
* OSX 10.6 ("Snow Leopard") or 10.7 ("Lion"), x86 and x86-64
|
||||||
* Windows (7, server 2008 r2) x86 only
|
|
||||||
* Linux (various distributions) x86 and x86-64
|
|
||||||
* OSX 10.6 ("Snow Leopard") or 10.7 ("Lion") x86 and x86-64
|
|
||||||
|
|
||||||
You may find other platforms work, but these are our "tier 1" supported
|
You may find that other platforms work, but these are our "tier 1"
|
||||||
build environments that are most likely to work. Further platforms will
|
supported build environments that are most likely to work.
|
||||||
be added to the list in the future via cross-compilation.
|
|
||||||
|
> ***Note:*** Windows users should read the detailed
|
||||||
|
> [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 in this tutorial.
|
||||||
|
|
||||||
To build from source you will also need the following prerequisite
|
To build from source you will also need the following prerequisite
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
* g++ 4.4 or clang++ 3.x
|
* g++ 4.4 or clang++ 3.x
|
||||||
* python 2.6 or later
|
* python 2.6 or later (but not 3.x)
|
||||||
* perl 5.0 or later
|
* perl 5.0 or later
|
||||||
* gnu make 3.81 or later
|
* gnu make 3.81 or later
|
||||||
* curl
|
* curl
|
||||||
|
|
||||||
Assuming you're on a relatively modern *nix system and have met the
|
Assuming you're on a relatively modern *nix system and have met the
|
||||||
prerequisites, something along these lines should work. Building from
|
prerequisites, something along these lines should work.
|
||||||
source on Windows requires some extra steps: please see the [getting
|
|
||||||
started][wiki-get-started] page on the Rust wiki.
|
|
||||||
|
|
||||||
~~~~ {.notrust}
|
~~~~ {.notrust}
|
||||||
$ wget http://dl.rust-lang.org/dist/rust-0.4.tar.gz
|
$ wget http://dl.rust-lang.org/dist/rust-0.4.tar.gz
|
||||||
@ -118,8 +118,9 @@ When complete, `make install` will place the following programs into
|
|||||||
* `rustdoc`, the API-documentation tool
|
* `rustdoc`, the API-documentation tool
|
||||||
* `cargo`, the Rust package manager
|
* `cargo`, the Rust package manager
|
||||||
|
|
||||||
[wiki-get-started]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
|
[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
|
||||||
[tarball]: http://dl.rust-lang.org/dist/rust-0.4.tar.gz
|
[tarball]: http://dl.rust-lang.org/dist/rust-0.4.tar.gz
|
||||||
|
[win-exe]: http://dl.rust-lang.org/dist/rust-0.4-install.exe
|
||||||
|
|
||||||
## Compiling your first program
|
## Compiling your first program
|
||||||
|
|
||||||
@ -128,91 +129,137 @@ we have a file `hello.rs` containing this program:
|
|||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
fn main() {
|
fn main() {
|
||||||
io::println("hello world!");
|
io::println("hello? yes, this is rust");
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
If the Rust compiler was installed successfully, running `rustc
|
If the Rust compiler was installed successfully, running `rustc
|
||||||
hello.rs` will produce a binary called `hello` (or `hello.exe`).
|
hello.rs` will produce an executable called `hello` (or `hello.exe` on
|
||||||
|
Windows) which, upon running, will likely do exactly what you expect
|
||||||
|
(unless you are on Windows, in which case what it does is subject
|
||||||
|
to local weather conditions).
|
||||||
|
|
||||||
If you modify the program to make it invalid (for example, by changing
|
> ***Note:*** That may or may not be hyperbole, but there are some
|
||||||
`io::println` to some nonexistent function), and then compile it,
|
> 'gotchas' to be aware of on Windows. First, the MinGW environment
|
||||||
you'll see an error message like this:
|
> must be set up perfectly. Please read [the
|
||||||
|
> wiki][wiki-started]. Second, `rustc` may need to be [referred to as
|
||||||
|
> `rustc.exe`][bug-3319]. It's a bummer, I know, and I am so very
|
||||||
|
> sorry.
|
||||||
|
|
||||||
|
[bug-3319]: https://github.com/mozilla/rust/issues/3319
|
||||||
|
[wiki-started]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
|
||||||
|
|
||||||
|
The Rust compiler tries to provide useful information when it runs
|
||||||
|
into an error. If you modify the program to make it invalid (for
|
||||||
|
example, by changing `io::println` to some nonexistent function), and
|
||||||
|
then compile it, you'll see an error message like this:
|
||||||
|
|
||||||
~~~~ {.notrust}
|
~~~~ {.notrust}
|
||||||
hello.rs:2:4: 2:16 error: unresolved name: io::print_it
|
hello.rs:2:4: 2:16 error: unresolved name: io::print_it
|
||||||
hello.rs:2 io::print_it("hello world!");
|
hello.rs:2 io::print_it("hello? yes, this is rust");
|
||||||
^~~~~~~~~~~~
|
^~~~~~~~~~~~
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The Rust compiler tries to provide useful information when it runs
|
In its simplest form, a Rust program is a `.rs` file with some types
|
||||||
into an error.
|
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
|
||||||
## Anatomy of a Rust program
|
|
||||||
|
|
||||||
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
|
|
||||||
declaration to appear at the top level of the file—all statements must
|
declaration to appear at the top level of the file—all statements must
|
||||||
live inside a function.
|
live inside a function. Rust programs can also be compiled as
|
||||||
|
libraries, and included in other programs. The `extern mod std`
|
||||||
Rust programs can also be compiled as libraries, and included in other
|
directive that appears at the top of many examples imports the
|
||||||
programs. The `extern mod std` directive that appears at the top of a lot of
|
[standard library][std], described in more detail [later
|
||||||
examples imports the [standard library][std]. This is described in more
|
on](#modules-and-crates).
|
||||||
detail [later on](#modules-and-crates).
|
|
||||||
|
|
||||||
[std]: http://doc.rust-lang.org/doc/std
|
[std]: http://doc.rust-lang.org/doc/std
|
||||||
|
|
||||||
## Editing Rust code
|
## Editing Rust code
|
||||||
|
|
||||||
There are Vim highlighting and indentation scripts in the Rust source
|
There are vim highlighting and indentation scripts in the Rust source
|
||||||
distribution under `src/etc/vim/`, and an emacs mode under
|
distribution under `src/etc/vim/`. There is an emacs mode under
|
||||||
`src/etc/emacs/`. There is a package for Sublime Text 2 at
|
`src/etc/emacs/` called `rust-mode`, but do read the instructions
|
||||||
[github.com/dbp/sublime-rust](http://github.com/dbp/sublime-rust), also
|
included in that directory. In particular, if you are running emacs
|
||||||
available through [package control](http://wbond.net/sublime_packages/package_control).
|
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
|
||||||
|
[Sublime Package Control][sublime-pkg].
|
||||||
|
|
||||||
Other editors are not provided for yet. If you end up writing a Rust
|
Other editors are not provided for yet. If you end up writing a Rust
|
||||||
mode for your favorite editor, let us know so that we can link to it.
|
mode for your favorite editor, let us know so that we can link to it.
|
||||||
|
|
||||||
|
[sublime]: http://github.com/dbp/sublime-rust
|
||||||
|
[sublime-pkg]: http://wbond.net/sublime_packages/package_control
|
||||||
|
|
||||||
# Syntax Basics
|
# Syntax Basics
|
||||||
|
|
||||||
## Braces
|
|
||||||
|
|
||||||
Assuming you've programmed in any C-family language (C++, Java,
|
Assuming you've programmed in any C-family language (C++, Java,
|
||||||
JavaScript, C#, or PHP), Rust will feel familiar. The main surface
|
JavaScript, C#, or PHP), Rust will feel familiar. Code is arranged
|
||||||
difference to be aware of is that the bodies of `if` statements and of
|
in blocks delineated by curly braces; there are control structures
|
||||||
`while` loops *have* to be wrapped in brackets. Single-statement,
|
for branching and looping, like the familiar `if` and `when`; function
|
||||||
bracket-less bodies are not allowed.
|
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.
|
||||||
|
|
||||||
Accounting for these differences, the surface syntax of Rust
|
The main surface difference to be aware of is that the condition at
|
||||||
statements and expressions is C-like. Function calls are written
|
the head of control structures like `if` and `while` do not require
|
||||||
`myfunc(arg1, arg2)`, operators have mostly the same name and
|
paretheses, while their bodies *must* be wrapped in
|
||||||
precedence that they have in C, comments look the same, and constructs
|
brackets. Single-statement, bracket-less bodies are not allowed.
|
||||||
like `if` and `while` are available:
|
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# fn it_works() {}
|
# fn calibrate_universe() -> bool { true }
|
||||||
# fn abort() {}
|
# fn party_on() {}
|
||||||
|
# fn panic() {}
|
||||||
fn main() {
|
fn main() {
|
||||||
while true {
|
while calibrate_universe() {
|
||||||
/* Ensure that basic math works. */
|
/* Ensure that basic math still operates is expected */
|
||||||
if 2*20 > 30 {
|
if 2*20 > 30 {
|
||||||
// Everything is OK.
|
party_on(); // That's a relief
|
||||||
it_works();
|
|
||||||
} else {
|
} else {
|
||||||
abort();
|
panic();
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
The `let` keyword, introduces a local variable. By default, variables
|
||||||
|
are immutable. `let mut` can be used to introduce a local variable
|
||||||
|
that can be reassigned.
|
||||||
|
|
||||||
|
~~~~
|
||||||
|
let hi = "hi";
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
while count < 10 {
|
||||||
|
io::println(hi);
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Although Rust can almost always infer the types of local variables, it
|
||||||
|
can help readability to specify a variable's type by following it with
|
||||||
|
a colon, then the type name. Local variables may shadow earlier
|
||||||
|
declarations, making the earlier variables inaccessible.
|
||||||
|
|
||||||
|
~~~~
|
||||||
|
let my_favorite_value: float = 57.8;
|
||||||
|
let my_favorite_value: int = my_favorite_value as int;
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
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;
|
||||||
|
type MyType = int; // built-in types though are _not_ camel case
|
||||||
|
~~~
|
||||||
|
|
||||||
## Expression syntax
|
## Expression syntax
|
||||||
|
|
||||||
Though it isn't apparent in all code, there is a fundamental
|
Though it isn't apparent in all code, there is a fundamental
|
||||||
difference between Rust's syntax and its predecessors in this family
|
difference between Rust's syntax and its predecessors in this family
|
||||||
of languages. Many constructs that are statements in C are expressions
|
of languages. Many constructs that are statements in C are expressions
|
||||||
in Rust. This allows Rust to be more expressive. For example, you might
|
in Rust, allowing code to be more concise. For example, you might
|
||||||
write a piece of code like this:
|
write a piece of code like this:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
@ -231,16 +278,20 @@ But, in Rust, you don't have to repeat the name `price`:
|
|||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# let item = "salad";
|
# let item = "salad";
|
||||||
let price = if item == "salad" { 3.50 }
|
let price = if item == "salad" {
|
||||||
else if item == "muffin" { 2.25 }
|
3.50
|
||||||
else { 2.00 };
|
} else if item == "muffin" {
|
||||||
|
2.25
|
||||||
|
} else {
|
||||||
|
2.00
|
||||||
|
};
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Both pieces of code are exactly equivalent—they assign a value to `price`
|
Both pieces of code are exactly equivalent—they assign a value to
|
||||||
depending on the condition that holds. Note that the semicolons are omitted
|
`price` depending on the condition that holds. Note that the
|
||||||
from the second snippet. This is important; the lack of a semicolon after the
|
semicolons are omitted from the blocks in the second snippet. This is
|
||||||
last statement in a braced block gives the whole block the value of that last
|
important; the lack of a semicolon after the last statement in a
|
||||||
expression.
|
braced block gives the whole block the value of that last expression.
|
||||||
|
|
||||||
Put another way, the semicolon in Rust *ignores the value of an expression*.
|
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
|
Thus, if the branches of the `if` had looked like `{ 4; }`, the above example
|
||||||
@ -248,14 +299,16 @@ would simply assign nil (void) to `price`. But without the semicolon, each
|
|||||||
branch has a different value, and `price` gets the value of the branch that
|
branch has a different value, and `price` gets the value of the branch that
|
||||||
was taken.
|
was taken.
|
||||||
|
|
||||||
This feature also works for function bodies. This function returns a boolean:
|
|
||||||
|
|
||||||
~~~~
|
|
||||||
fn is_four(x: int) -> bool { x == 4 }
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
In short, everything that's not a declaration (`let` for variables,
|
In short, everything that's not a declaration (`let` for variables,
|
||||||
`fn` for functions, et cetera) is an expression.
|
`fn` for functions, et cetera) is an expression, including function bodies.
|
||||||
|
|
||||||
|
~~~~
|
||||||
|
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
|
||||||
|
}
|
||||||
|
~~~~
|
||||||
|
|
||||||
If all those things are expressions, you might conclude that you have
|
If all those things are expressions, you might conclude that you have
|
||||||
to add a terminating semicolon after *every* statement, even ones that
|
to add a terminating semicolon after *every* statement, even ones that
|
||||||
@ -264,48 +317,40 @@ That is not the case, though. Expressions that end in a block only
|
|||||||
need a semicolon if that block contains a trailing expression. `while`
|
need a semicolon if that block contains a trailing expression. `while`
|
||||||
loops do not allow trailing expressions, and `if` statements tend to
|
loops do not allow trailing expressions, and `if` statements tend to
|
||||||
only have a trailing expression when you want to use their value for
|
only have a trailing expression when you want to use their value for
|
||||||
something—in which case you'll have embedded it in a bigger statement,
|
something—in which case you'll have embedded it in a bigger statement.
|
||||||
like the `let x = ...` example above.
|
|
||||||
|
|
||||||
## Identifiers
|
~~~
|
||||||
|
# fn foo() -> bool { true }
|
||||||
|
# fn bar() -> bool { true }
|
||||||
|
# fn baz() -> bool { true }
|
||||||
|
|
||||||
Rust identifiers follow the same rules as C; they start with an alphabetic
|
// `let` is not an expression, so it is semi-colon terminated;
|
||||||
character or an underscore, and after that may contain any sequence of
|
let x = foo();
|
||||||
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 beginning types with a capital
|
|
||||||
letter.
|
|
||||||
|
|
||||||
The double-colon (`::`) is used as a module separator, so
|
// When used in statement position, bracy expressions do not
|
||||||
`io::println` means 'the thing named `println` in the module
|
// usually need to be semicolon terminated
|
||||||
named `io`.
|
if x {
|
||||||
|
bar();
|
||||||
|
} else {
|
||||||
|
baz();
|
||||||
|
} // No semi-colon
|
||||||
|
|
||||||
## Variable declaration
|
// 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
|
||||||
|
|
||||||
The `let` keyword, as we've seen, introduces a local variable. Local
|
// An `if` embedded in `let` again requires a semicolon to terminate
|
||||||
variables are immutable by default: `let mut` can be used to introduce
|
// the `let` statement
|
||||||
a local variable that can be reassigned. Global constants can be
|
let y = if x { foo() } else { bar() };
|
||||||
defined with `const`:
|
~~~
|
||||||
|
|
||||||
~~~~
|
This may sound a bit intricate, but it is super-useful, and it will
|
||||||
const REPEAT: int = 5;
|
grow on you (hopefully).
|
||||||
fn main() {
|
|
||||||
let hi = "Hi!";
|
|
||||||
let mut count = 0;
|
|
||||||
while count < REPEAT {
|
|
||||||
io::println(hi);
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Local variables may shadow earlier declarations, making the earlier variables
|
|
||||||
inaccessible.
|
|
||||||
|
|
||||||
~~~~
|
|
||||||
let my_favorite_value: float = 57.8;
|
|
||||||
let my_favorite_value: int = my_favorite_value as int;
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
## Types
|
## Types
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user