Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
More looking at the tutorial, small changes
  • Loading branch information
killerswan authored and brson committed Oct 5, 2012
1 parent 2dfd822 commit fafce9a
Showing 1 changed file with 61 additions and 59 deletions.
120 changes: 61 additions & 59 deletions doc/tutorial.md
Expand Up @@ -329,7 +329,6 @@ something—in which case you'll have embedded it in a bigger statement.
# fn foo() -> bool { true }
# fn bar() -> bool { true }
# fn baz() -> bool { true }
// `let` is not an expression, so it is semi-colon terminated;
let x = foo();
Expand Down Expand Up @@ -711,8 +710,8 @@ Structs can be destructured in `match` patterns. The basic syntax is
# struct Point { x: float, y: float }
# let mypoint = Point { x: 0.0, y: 0.0 };
match mypoint {
Point { x: 0.0, y: y } => { io::println(y.to_str()); }
Point { x: x, y: y } => { io::println(x.to_str() + " " + y.to_str()); }
Point { x: 0.0, y: yy } => { io::println(yy.to_str()); }
Point { x: xx, y: yy } => { io::println(xx.to_str() + " " + yy.to_str()); }
}
~~~~
Expand Down Expand Up @@ -802,7 +801,7 @@ dereference (`*`) unary operator:
~~~~
# enum GizmoId = int;
let my_gizmo_id = GizmoId(10);
let my_gizmo_id: GizmoId = GizmoId(10);
let id_int: int = *my_gizmo_id;
~~~~
Expand Down Expand Up @@ -863,12 +862,8 @@ back to [later](#modules-and-crates)). They are introduced with the
the return type follows the arrow.
~~~~
fn repeat(string: &str, count: int) -> ~str {
let mut result = ~"";
for count.times {
result += string;
}
return result;
fn line(a: int, b: int, x: int) -> int {
return a*x + b;
}
~~~~
Expand All @@ -889,10 +884,8 @@ fn int_to_str(i: int) -> ~str {
~~~~
~~~~
# const copernicus: int = 0;
fn int_to_str(i: int) -> ~str {
if i == copernicus { ~"tube sock" }
else { ~"violin" }
fn line(a: int, b: int, x: int) -> int {
a*x + b
}
~~~~
Expand All @@ -906,6 +899,16 @@ fn do_nothing_the_hard_way() -> () { return (); }
fn do_nothing_the_easy_way() { }
~~~~
Ending the function with a semicolon like so is equivalent to returning `()`.
~~~~
fn line(a: int, b: int, x: int) -> int { a*x + b }
fn oops(a: int, b: int, x: int) -> () { a*x + b; }

assert 8 == line(5,3,1);
assert () == oops(5,3,1);
~~~~
Methods are like functions, except that they are defined for a specific
'self' type (like 'this' in C++). Calling a method is done with
dot notation, as in `my_vec.len()`. Methods may be defined on most
Expand Down Expand Up @@ -1005,7 +1008,7 @@ easy for programmers to reason about. Heap isolation has the
additional benefit that garbage collection must only be done
per-heap. Rust never "stops the world" to reclaim memory.
Complete isolation of heaps between tasks implies that any data
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. Because of this, Rust also
Expand Down Expand Up @@ -1117,6 +1120,9 @@ If you really want to copy a unique box you must say so explicitly.
~~~~
let x = ~10;
let y = copy x;

let z = *x + *y;
assert z = 20;
~~~~
This is where the 'move' operator comes in. It is similar to
Expand All @@ -1125,9 +1131,11 @@ from `x` to `y`, without violating the constraint that it only has a
single owner (if you used assignment instead of the move operator, the
box would, in principle, be copied).
~~~~
~~~~ {.ignore}
let x = ~10;
let y = move x;
let z = *x + *y; // would cause an error: use of moved variable: `x`
~~~~

Owned boxes, when they do not contain any managed boxes, can be sent
Expand Down Expand Up @@ -1265,7 +1273,7 @@ also done with square brackets (zero-based):
# BananaMania, Beaver, Bittersweet };
# fn draw_scene(c: Crayon) { }
let crayons = [BananaMania, Beaver, Bittersweet];
let crayons: [Crayon] = [BananaMania, Beaver, Bittersweet];
match crayons[0] {
Bittersweet => draw_scene(crayons[0]),
_ => ()
Expand All @@ -1282,7 +1290,7 @@ elements. Mutable vector literals are written `[mut]` (empty) or `[mut
# Aquamarine, Asparagus, AtomicTangerine,
# BananaMania, Beaver, Bittersweet };
let crayons = [mut BananaMania, Beaver, Bittersweet];
let crayons: [mut Crayon] = [mut BananaMania, Beaver, Bittersweet];
crayons[0] = AtomicTangerine;
~~~~

Expand Down Expand Up @@ -1318,8 +1326,8 @@ my_crayons += your_crayons;
> not well supported yet, owned vectors are often the most
> usable.
Strings are simply vectors of `[u8]`, though they have a distinct
type. They support most of the same allocation aptions as
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, e.g.
`"foo"` is treated differently than a comparable vector (`[foo]`).
Where
Expand All @@ -1328,7 +1336,7 @@ Where
// A plain string is a slice to read-only (static) memory
let stack_crayons: &str = "Almond, AntiqueBrass, Apricot";
// The same thing, but without
// The same thing, but with the `&`
let stack_crayons: &str = &"Almond, AntiqueBrass, Apricot";
// A local heap (managed) string
Expand Down Expand Up @@ -1511,9 +1519,12 @@ call_twice(bare_function);
## Do syntax

Closures in Rust are frequently used in combination with higher-order
functions to simulate control structures like `if` and
`loop`. Consider this function that iterates over a vector of
The `do` expression is syntactic sugar for use with functions which
take a closure as a final argument, because closures in Rust
are so frequently used in combination with higher-order
functions.

Consider this function which iterates over a vector of
integers, passing in a pointer to each integer in the vector:

~~~~
Expand Down Expand Up @@ -1558,8 +1569,7 @@ do each(&[1, 2, 3]) |n| {
The call is prefixed with the keyword `do` and, instead of writing the
final closure inside the argument list it is moved outside of the
parenthesis where it looks visually more like a typical block of
code. The `do` expression is purely syntactic sugar for a call that
takes a final closure argument.
code.

`do` is often used for task spawning.

Expand Down Expand Up @@ -1653,6 +1663,10 @@ fn contains(v: &[int], elt: int) -> bool {

`for` syntax only works with stack closures.

> ***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.
# Generics

Throughout this tutorial, we've been defining functions that act only on
Expand Down Expand Up @@ -2057,6 +2071,9 @@ The compiler will now look for `poultry/chicken.rs` and
and `poultry::turkey`. You can also provide a `poultry.rs` to add
content to the `poultry` module itself.

The compiler then builds the crate as a platform-specific shared library or
executable which can be distributed.

## Using other crates

Having compiled a crate that contains the `#[crate_type = "lib"]`
Expand Down Expand Up @@ -2111,22 +2128,22 @@ Now for something that you can actually compile yourself. We have
these two files:

~~~~
// mylib.rs
#[link(name = "mylib", vers = "1.0")];
fn world() -> ~str { ~"world" }
// world.rs
#[link(name = "world", vers = "1.0")];
fn explore() -> ~str { ~"world" }
~~~~

~~~~ {.ignore}
// main.rs
extern mod mylib;
fn main() { io::println(~"hello " + mylib::world()); }
extern mod world;
fn main() { io::println(~"hello " + world::explore()); }
~~~~

Now compile and run like this (adjust to your platform if necessary):

~~~~ {.notrust}
> rustc --lib mylib.rs
> rustc main.rs -L .
> rustc --lib world.rs # compiles libworld-94839cbfe144198-1.0.so
> rustc main.rs -L . # compiles main
> ./main
"hello world"
~~~~
Expand All @@ -2146,12 +2163,14 @@ fn main() {
}
~~~~


It is also possible to import just the name of a module (`use
std::list;`, then use `list::find`), to import all identifiers exported
by a given module (`use io::*`), or to import a specific set
of identifiers (`use math::{min, max, pi}`).

You can rename an identifier when importing using the `=` operator:
Rust uses different namespaces for modules, types, and values. You
can also rename an identifier when importing using the `=` operator:

~~~~
use prnt = io::println;
Expand All @@ -2175,27 +2194,6 @@ This defines a rock-solid encryption algorithm. Code outside of the
module can refer to the `enc::encrypt` and `enc::decrypt` identifiers
just fine, but it does not have access to `enc::super_secret_number`.

## Namespaces

Rust uses three different namespaces: one for modules, one for types,
and one for values. This means that this code is valid:

~~~~
#[legacy_exports]
mod buffalo {
type buffalo = int;
fn buffalo<buffalo>(+buffalo: buffalo) -> buffalo { buffalo }
}
fn main() {
let buffalo: buffalo::buffalo = 1;
buffalo::buffalo::<buffalo::buffalo>(buffalo::buffalo(buffalo));
}
~~~~

You don't want to write things like that, but it *is* very practical
to not have to worry about name clashes between types, values, and
modules.

## Resolution

The resolution process in Rust simply goes up the chain of contexts,
Expand All @@ -2211,21 +2209,25 @@ Identifiers can shadow each other. In this program, `x` is of type
type MyType = ~str;
fn main() {
type MyType = int;
let x: MyType;
let x: MyType = 17;
}
~~~~

An `use` directive will only import into the namespaces for which
identifiers are actually found. Consider this example:

~~~~
mod foo { fn bar() {} }
fn baz() {
let bar = 10u;
mod foo {
fn bar() {}
}
fn main() {
let bar = 10;
{
use foo::bar;
let quux = bar;
assert quux == 10;
}
}
~~~~
Expand Down

0 comments on commit fafce9a

Please sign in to comment.