More looking at the tutorial, small changes

This commit is contained in:
Kevin Cantu 2012-10-04 12:41:45 -07:00 committed by Brian Anderson
parent 2dfd822962
commit fafce9ae37
1 changed files with 61 additions and 59 deletions

View File

@ -329,7 +329,6 @@ something—in which case you'll have embedded it in a bigger statement.
# fn foo() -> bool { true } # fn foo() -> bool { true }
# fn bar() -> bool { true } # fn bar() -> bool { true }
# fn baz() -> bool { true } # fn baz() -> bool { true }
// `let` is not an expression, so it is semi-colon terminated; // `let` is not an expression, so it is semi-colon terminated;
let x = foo(); let x = foo();
@ -711,8 +710,8 @@ Structs can be destructured in `match` patterns. The basic syntax is
# struct Point { x: float, y: float } # struct Point { x: float, y: float }
# let mypoint = Point { x: 0.0, y: 0.0 }; # let mypoint = Point { x: 0.0, y: 0.0 };
match mypoint { match mypoint {
Point { x: 0.0, y: y } => { io::println(y.to_str()); } Point { x: 0.0, y: yy } => { io::println(yy.to_str()); }
Point { x: x, y: y } => { io::println(x.to_str() + " " + y.to_str()); } Point { x: xx, y: yy } => { io::println(xx.to_str() + " " + yy.to_str()); }
} }
~~~~ ~~~~
@ -802,7 +801,7 @@ dereference (`*`) unary operator:
~~~~ ~~~~
# enum GizmoId = int; # enum GizmoId = int;
let my_gizmo_id = GizmoId(10); let my_gizmo_id: GizmoId = GizmoId(10);
let id_int: int = *my_gizmo_id; let id_int: int = *my_gizmo_id;
~~~~ ~~~~
@ -863,12 +862,8 @@ back to [later](#modules-and-crates)). They are introduced with the
the return type follows the arrow. the return type follows the arrow.
~~~~ ~~~~
fn repeat(string: &str, count: int) -> ~str { fn line(a: int, b: int, x: int) -> int {
let mut result = ~""; return a*x + b;
for count.times {
result += string;
}
return result;
} }
~~~~ ~~~~
@ -889,10 +884,8 @@ fn int_to_str(i: int) -> ~str {
~~~~ ~~~~
~~~~ ~~~~
# const copernicus: int = 0; fn line(a: int, b: int, x: int) -> int {
fn int_to_str(i: int) -> ~str { a*x + b
if i == copernicus { ~"tube sock" }
else { ~"violin" }
} }
~~~~ ~~~~
@ -906,6 +899,16 @@ fn do_nothing_the_hard_way() -> () { return (); }
fn do_nothing_the_easy_way() { } 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 Methods are like functions, except that they are defined for a specific
'self' type (like 'this' in C++). Calling a method is done with '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 dot notation, as in `my_vec.len()`. Methods may be defined on most
@ -1005,7 +1008,7 @@ easy for programmers to reason about. Heap isolation has the
additional benefit that garbage collection must only be done additional benefit that garbage collection must only be done
per-heap. Rust never "stops the world" to reclaim memory. 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 transferred between tasks must be copied. While this is a fine and
useful way to implement communication between tasks, it is also very useful way to implement communication between tasks, it is also very
inefficient for large data structures. Because of this, Rust also inefficient for large data structures. Because of this, Rust also
@ -1117,6 +1120,9 @@ If you really want to copy a unique box you must say so explicitly.
~~~~ ~~~~
let x = ~10; let x = ~10;
let y = copy x; let y = copy x;
let z = *x + *y;
assert z = 20;
~~~~ ~~~~
This is where the 'move' operator comes in. It is similar to This is where the 'move' operator comes in. It is similar to
@ -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 single owner (if you used assignment instead of the move operator, the
box would, in principle, be copied). box would, in principle, be copied).
~~~~ ~~~~ {.ignore}
let x = ~10; let x = ~10;
let y = move x; 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 Owned boxes, when they do not contain any managed boxes, can be sent
@ -1265,7 +1273,7 @@ also done with square brackets (zero-based):
# BananaMania, Beaver, Bittersweet }; # BananaMania, Beaver, Bittersweet };
# fn draw_scene(c: Crayon) { } # fn draw_scene(c: Crayon) { }
let crayons = [BananaMania, Beaver, Bittersweet]; let crayons: [Crayon] = [BananaMania, Beaver, Bittersweet];
match crayons[0] { match crayons[0] {
Bittersweet => draw_scene(crayons[0]), Bittersweet => draw_scene(crayons[0]),
_ => () _ => ()
@ -1282,7 +1290,7 @@ elements. Mutable vector literals are written `[mut]` (empty) or `[mut
# Aquamarine, Asparagus, AtomicTangerine, # Aquamarine, Asparagus, AtomicTangerine,
# BananaMania, Beaver, Bittersweet }; # BananaMania, Beaver, Bittersweet };
let crayons = [mut BananaMania, Beaver, Bittersweet]; let crayons: [mut Crayon] = [mut BananaMania, Beaver, Bittersweet];
crayons[0] = AtomicTangerine; crayons[0] = AtomicTangerine;
~~~~ ~~~~
@ -1318,8 +1326,8 @@ my_crayons += your_crayons;
> not well supported yet, owned vectors are often the most > not well supported yet, owned vectors are often the most
> usable. > usable.
Strings are simply vectors of `[u8]`, though they have a distinct Strings are implemented with vectors of `[u8]`, though they have a distinct
type. They support most of the same allocation aptions as type. They support most of the same allocation options as
vectors, though the string literal without a storage sigil, e.g. vectors, though the string literal without a storage sigil, e.g.
`"foo"` is treated differently than a comparable vector (`[foo]`). `"foo"` is treated differently than a comparable vector (`[foo]`).
Where Where
@ -1328,7 +1336,7 @@ Where
// A plain string is a slice to read-only (static) memory // A plain string is a slice to read-only (static) memory
let stack_crayons: &str = "Almond, AntiqueBrass, Apricot"; 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"; let stack_crayons: &str = &"Almond, AntiqueBrass, Apricot";
// A local heap (managed) string // A local heap (managed) string
@ -1511,9 +1519,12 @@ call_twice(bare_function);
## Do syntax ## Do syntax
Closures in Rust are frequently used in combination with higher-order The `do` expression is syntactic sugar for use with functions which
functions to simulate control structures like `if` and take a closure as a final argument, because closures in Rust
`loop`. Consider this function that iterates over a vector of 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: integers, passing in a pointer to each integer in the vector:
~~~~ ~~~~
@ -1558,8 +1569,7 @@ do each(&[1, 2, 3]) |n| {
The call is prefixed with the keyword `do` and, instead of writing the 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 final closure inside the argument list it is moved outside of the
parenthesis where it looks visually more like a typical block of parenthesis where it looks visually more like a typical block of
code. The `do` expression is purely syntactic sugar for a call that code.
takes a final closure argument.
`do` is often used for task spawning. `do` is often used for task spawning.
@ -1653,6 +1663,10 @@ fn contains(v: &[int], elt: int) -> bool {
`for` syntax only works with stack closures. `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 # Generics
Throughout this tutorial, we've been defining functions that act only on Throughout this tutorial, we've been defining functions that act only on
@ -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 and `poultry::turkey`. You can also provide a `poultry.rs` to add
content to the `poultry` module itself. 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 ## Using other crates
Having compiled a crate that contains the `#[crate_type = "lib"]` Having compiled a crate that contains the `#[crate_type = "lib"]`
@ -2111,22 +2128,22 @@ Now for something that you can actually compile yourself. We have
these two files: these two files:
~~~~ ~~~~
// mylib.rs // world.rs
#[link(name = "mylib", vers = "1.0")]; #[link(name = "world", vers = "1.0")];
fn world() -> ~str { ~"world" } fn explore() -> ~str { ~"world" }
~~~~ ~~~~
~~~~ {.ignore} ~~~~ {.ignore}
// main.rs // main.rs
extern mod mylib; extern mod world;
fn main() { io::println(~"hello " + mylib::world()); } fn main() { io::println(~"hello " + world::explore()); }
~~~~ ~~~~
Now compile and run like this (adjust to your platform if necessary): Now compile and run like this (adjust to your platform if necessary):
~~~~ {.notrust} ~~~~ {.notrust}
> rustc --lib mylib.rs > rustc --lib world.rs # compiles libworld-94839cbfe144198-1.0.so
> rustc main.rs -L . > rustc main.rs -L . # compiles main
> ./main > ./main
"hello world" "hello world"
~~~~ ~~~~
@ -2146,12 +2163,14 @@ fn main() {
} }
~~~~ ~~~~
It is also possible to import just the name of a module (`use It is also possible to import just the name of a module (`use
std::list;`, then use `list::find`), to import all identifiers exported std::list;`, then use `list::find`), to import all identifiers exported
by a given module (`use io::*`), or to import a specific set by a given module (`use io::*`), or to import a specific set
of identifiers (`use math::{min, max, pi}`). 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; use prnt = io::println;
@ -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 module can refer to the `enc::encrypt` and `enc::decrypt` identifiers
just fine, but it does not have access to `enc::super_secret_number`. 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 ## Resolution
The resolution process in Rust simply goes up the chain of contexts, The resolution process in Rust simply goes up the chain of contexts,
@ -2211,7 +2209,7 @@ Identifiers can shadow each other. In this program, `x` is of type
type MyType = ~str; type MyType = ~str;
fn main() { fn main() {
type MyType = int; type MyType = int;
let x: MyType; let x: MyType = 17;
} }
~~~~ ~~~~
@ -2219,13 +2217,17 @@ An `use` directive will only import into the namespaces for which
identifiers are actually found. Consider this example: identifiers are actually found. Consider this example:
~~~~ ~~~~
mod foo { fn bar() {} } mod foo {
fn baz() { fn bar() {}
let bar = 10u; }
fn main() {
let bar = 10;
{ {
use foo::bar; use foo::bar;
let quux = bar; let quux = bar;
assert quux == 10;
} }
} }
~~~~ ~~~~