docs: Modernize tutorial snippets
This commit is contained in:
parent
da5033f991
commit
65cdfa4a21
218
doc/tutorial.md
218
doc/tutorial.md
@ -815,33 +815,33 @@ Enum variants need not have type parameters. This, for example, is
|
||||
equivalent to a C enum:
|
||||
|
||||
~~~~
|
||||
enum direction {
|
||||
north,
|
||||
east,
|
||||
south,
|
||||
west
|
||||
enum Direction {
|
||||
North,
|
||||
East,
|
||||
South,
|
||||
West
|
||||
}
|
||||
~~~~
|
||||
|
||||
This will define `north`, `east`, `south`, and `west` as constants,
|
||||
all of which have type `direction`.
|
||||
This will define `North`, `East`, `South`, and `West` as constants,
|
||||
all of which have type `Direction`.
|
||||
|
||||
When an enum is C-like, that is, when none of the variants have
|
||||
parameters, it is possible to explicitly set the discriminator values
|
||||
to an integer value:
|
||||
|
||||
~~~~
|
||||
enum color {
|
||||
red = 0xff0000,
|
||||
green = 0x00ff00,
|
||||
blue = 0x0000ff
|
||||
enum Color {
|
||||
Red = 0xff0000,
|
||||
Green = 0x00ff00,
|
||||
Blue = 0x0000ff
|
||||
}
|
||||
~~~~
|
||||
|
||||
If an explicit discriminator is not specified for a variant, the value
|
||||
defaults to the value of the previous variant plus one. If the first
|
||||
variant does not have a discriminator, it defaults to 0. For example,
|
||||
the value of `north` is 0, `east` is 1, etc.
|
||||
the value of `North` is 0, `East` is 1, etc.
|
||||
|
||||
When an enum is C-like the `as` cast operator can be used to get the
|
||||
discriminator's value.
|
||||
@ -853,21 +853,21 @@ used to define new types in such a way that the new name is not just a
|
||||
synonym for an existing type, but its own distinct type. If you say:
|
||||
|
||||
~~~~
|
||||
enum gizmo_id = int;
|
||||
enum GizmoId = int;
|
||||
~~~~
|
||||
|
||||
That is a shorthand for this:
|
||||
|
||||
~~~~
|
||||
enum gizmo_id { gizmo_id(int) }
|
||||
enum GizmoId { GizmoId(int) }
|
||||
~~~~
|
||||
|
||||
Enum types like this can have their content extracted with the
|
||||
dereference (`*`) unary operator:
|
||||
|
||||
~~~~
|
||||
# enum gizmo_id = int;
|
||||
let my_gizmo_id = gizmo_id(10);
|
||||
# enum GizmoId = int;
|
||||
let my_gizmo_id = GizmoId(10);
|
||||
let id_int: int = *my_gizmo_id;
|
||||
~~~~
|
||||
|
||||
@ -878,12 +878,12 @@ get at their contents. All variant constructors can be used as
|
||||
patterns, as in this definition of `area`:
|
||||
|
||||
~~~~
|
||||
# type point = {x: float, y: float};
|
||||
# enum shape { circle(point, float), rectangle(point, point) }
|
||||
fn area(sh: shape) -> float {
|
||||
# type Point = {x: float, y: float};
|
||||
# enum Shape { Circle(Point, float), Rectangle(Point, Point) }
|
||||
fn area(sh: Shape) -> float {
|
||||
match sh {
|
||||
circle(_, size) => float::consts::pi * size * size,
|
||||
rectangle({x, y}, {x: x2, y: y2}) => (x2 - x) * (y2 - y)
|
||||
Circle(_, size) => float::consts::pi * size * size,
|
||||
Rectangle({x, y}, {x: x2, y: y2}) => (x2 - x) * (y2 - y)
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
@ -891,14 +891,14 @@ fn area(sh: shape) -> float {
|
||||
Another example, matching nullary enum variants:
|
||||
|
||||
~~~~
|
||||
# type point = {x: float, y: float};
|
||||
# enum direction { north, east, south, west }
|
||||
fn point_from_direction(dir: direction) -> point {
|
||||
# type Point = {x: float, y: float};
|
||||
# enum Direction { North, East, South, West }
|
||||
fn point_from_direction(dir: Direction) -> Point {
|
||||
match dir {
|
||||
north => {x: 0f, y: 1f},
|
||||
east => {x: 1f, y: 0f},
|
||||
south => {x: 0f, y: -1f},
|
||||
west => {x: -1f, y: 0f}
|
||||
North => {x: 0f, y: 1f},
|
||||
East => {x: 1f, y: 0f},
|
||||
South => {x: 0f, y: -1f},
|
||||
West => {x: -1f, y: 0f}
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
@ -1133,18 +1133,18 @@ values of the same type. Like other types in Rust, vectors can be
|
||||
stored on the stack, the local heap, or the exchange heap.
|
||||
|
||||
~~~
|
||||
enum crayon {
|
||||
almond, antique_brass, apricot,
|
||||
aquamarine, asparagus, atomic_tangerine,
|
||||
banana_mania, beaver, bittersweet
|
||||
enum Crayon {
|
||||
Almond, AntiqueBrass, Apricot,
|
||||
Aquamarine, Asparagus, AtomicTangerine,
|
||||
BananaMania, Beaver, Bittersweet
|
||||
}
|
||||
|
||||
// A stack vector of crayons
|
||||
let stack_crayons: &[crayon] = &[almond, antique_brass, apricot];
|
||||
let stack_crayons: &[Crayon] = &[Almond, AntiqueBrass, Apricot];
|
||||
// A local heap (shared) vector of crayons
|
||||
let local_crayons: @[crayon] = @[aquamarine, asparagus, atomic_tangerine];
|
||||
let local_crayons: @[Crayon] = @[Aquamarine, Asparagus, AtomicTangerine];
|
||||
// An exchange heap (unique) vector of crayons
|
||||
let exchange_crayons: ~[crayon] = ~[banana_mania, beaver, bittersweet];
|
||||
let exchange_crayons: ~[Crayon] = ~[BananaMania, Beaver, Bittersweet];
|
||||
~~~
|
||||
|
||||
> ***Note:*** Until recently Rust only had unique vectors, using the
|
||||
@ -1161,15 +1161,15 @@ Vector literals are enclosed in square brackets and dereferencing is
|
||||
also done with square brackets (zero-based):
|
||||
|
||||
~~~~
|
||||
# enum crayon { almond, antique_brass, apricot,
|
||||
# aquamarine, asparagus, atomic_tangerine,
|
||||
# banana_mania, beaver, bittersweet };
|
||||
# fn draw_scene(c: crayon) { }
|
||||
# enum Crayon { Almond, AntiqueBrass, Apricot,
|
||||
# Aquamarine, Asparagus, AtomicTangerine,
|
||||
# BananaMania, Beaver, Bittersweet };
|
||||
# fn draw_scene(c: Crayon) { }
|
||||
|
||||
let crayons = ~[banana_mania, beaver, bittersweet];
|
||||
let crayons = ~[BananaMania, Beaver, Bittersweet];
|
||||
match crayons[0] {
|
||||
bittersweet => draw_scene(crayons[0]),
|
||||
_ => ()
|
||||
Bittersweet => draw_scene(crayons[0]),
|
||||
_ => ()
|
||||
}
|
||||
~~~~
|
||||
|
||||
@ -1179,23 +1179,23 @@ elements. Mutable vector literals are written `~[mut]` (empty) or `~[mut
|
||||
1, 2, 3]` (with elements).
|
||||
|
||||
~~~~
|
||||
# enum crayon { almond, antique_brass, apricot,
|
||||
# aquamarine, asparagus, atomic_tangerine,
|
||||
# banana_mania, beaver, bittersweet };
|
||||
# enum Crayon { Almond, AntiqueBrass, Apricot,
|
||||
# Aquamarine, Asparagus, AtomicTangerine,
|
||||
# BananaMania, Beaver, Bittersweet };
|
||||
|
||||
let crayons = ~[mut banana_mania, beaver, bittersweet];
|
||||
crayons[0] = atomic_tangerine;
|
||||
let crayons = ~[mut BananaMania, Beaver, Bittersweet];
|
||||
crayons[0] = AtomicTangerine;
|
||||
~~~~
|
||||
|
||||
The `+` operator means concatenation when applied to vector types.
|
||||
|
||||
~~~~
|
||||
# enum crayon { almond, antique_brass, apricot,
|
||||
# aquamarine, asparagus, atomic_tangerine,
|
||||
# banana_mania, beaver, bittersweet };
|
||||
# enum Crayon { Almond, AntiqueBrass, Apricot,
|
||||
# Aquamarine, Asparagus, AtomicTangerine,
|
||||
# BananaMania, Beaver, Bittersweet };
|
||||
|
||||
let my_crayons = ~[almond, antique_brass, apricot];
|
||||
let your_crayons = ~[banana_mania, beaver, bittersweet];
|
||||
let my_crayons = ~[Almond, AntiqueBrass, Apricot];
|
||||
let your_crayons = ~[BananaMania, Beaver, Bittersweet];
|
||||
|
||||
let our_crayons = my_crayons + your_crayons;
|
||||
~~~~
|
||||
@ -1204,12 +1204,12 @@ The `+=` operator also works as expected, provided the assignee
|
||||
lives in a mutable slot.
|
||||
|
||||
~~~~
|
||||
# enum crayon { almond, antique_brass, apricot,
|
||||
# aquamarine, asparagus, atomic_tangerine,
|
||||
# banana_mania, beaver, bittersweet };
|
||||
# enum Crayon { Almond, AntiqueBrass, Apricot,
|
||||
# Aquamarine, Asparagus, AtomicTangerine,
|
||||
# BananaMania, Beaver, Bittersweet };
|
||||
|
||||
let mut my_crayons = ~[almond, antique_brass, apricot];
|
||||
let your_crayons = ~[banana_mania, beaver, bittersweet];
|
||||
let mut my_crayons = ~[Almond, AntiqueBrass, Apricot];
|
||||
let your_crayons = ~[BananaMania, Beaver, Bittersweet];
|
||||
|
||||
my_crayons += your_crayons;
|
||||
~~~~
|
||||
@ -1223,17 +1223,17 @@ brief look at a few common ones.
|
||||
|
||||
~~~
|
||||
# use io::println;
|
||||
# enum crayon {
|
||||
# almond, antique_brass, apricot,
|
||||
# aquamarine, asparagus, atomic_tangerine,
|
||||
# banana_mania, beaver, bittersweet
|
||||
# enum Crayon {
|
||||
# Almond, AntiqueBrass, Apricot,
|
||||
# Aquamarine, Asparagus, AtomicTangerine,
|
||||
# BananaMania, Beaver, Bittersweet
|
||||
# }
|
||||
# fn unwrap_crayon(c: crayon) -> int { 0 }
|
||||
# fn unwrap_crayon(c: Crayon) -> int { 0 }
|
||||
# fn eat_crayon_wax(i: int) { }
|
||||
# fn store_crayon_in_nasal_cavity(i: uint, c: crayon) { }
|
||||
# fn crayon_to_str(c: crayon) -> ~str { ~"" }
|
||||
# fn store_crayon_in_nasal_cavity(i: uint, c: Crayon) { }
|
||||
# fn crayon_to_str(c: Crayon) -> ~str { ~"" }
|
||||
|
||||
let crayons = ~[almond, antique_brass, apricot];
|
||||
let crayons = ~[Almond, AntiqueBrass, Apricot];
|
||||
|
||||
// Check the length of the vector
|
||||
assert crayons.len() == 3;
|
||||
@ -1625,7 +1625,7 @@ For example, we could declare the trait `to_str` for things that
|
||||
can be converted to a string, with a single method of the same name:
|
||||
|
||||
~~~~
|
||||
trait to_str {
|
||||
trait ToStr {
|
||||
fn to_str() -> ~str;
|
||||
}
|
||||
~~~~
|
||||
@ -1637,11 +1637,11 @@ is used. This defines implementations of `to_str` for the `int` and
|
||||
`~str` types.
|
||||
|
||||
~~~~
|
||||
# trait to_str { fn to_str() -> ~str; }
|
||||
impl int: to_str {
|
||||
# trait ToStr { fn to_str() -> ~str; }
|
||||
impl int: ToStr {
|
||||
fn to_str() -> ~str { int::to_str(self, 10u) }
|
||||
}
|
||||
impl ~str: to_str {
|
||||
impl ~str: ToStr {
|
||||
fn to_str() -> ~str { self }
|
||||
}
|
||||
~~~~
|
||||
@ -1662,8 +1662,8 @@ known at compile time, it is possible to specify 'bounds' for type
|
||||
parameters.
|
||||
|
||||
~~~~
|
||||
# trait to_str { fn to_str() -> ~str; }
|
||||
fn comma_sep<T: to_str>(elts: ~[T]) -> ~str {
|
||||
# trait ToStr { fn to_str() -> ~str; }
|
||||
fn comma_sep<T: ToStr>(elts: ~[T]) -> ~str {
|
||||
let mut result = ~"", first = true;
|
||||
for elts.each |elt| {
|
||||
if first { first = false; }
|
||||
@ -1688,11 +1688,11 @@ Traits may contain type parameters. A trait for
|
||||
generalized sequence types is:
|
||||
|
||||
~~~~
|
||||
trait seq<T> {
|
||||
trait Seq<T> {
|
||||
fn len() -> uint;
|
||||
fn iter(fn(T));
|
||||
}
|
||||
impl<T> ~[T]: seq<T> {
|
||||
impl<T> ~[T]: Seq<T> {
|
||||
fn len() -> uint { vec::len(self) }
|
||||
fn iter(b: fn(T)) {
|
||||
for self.each |elt| { b(elt); }
|
||||
@ -1716,11 +1716,11 @@ type parameter. An implementation of the trait for any given type
|
||||
trait describes types that support an equality operation:
|
||||
|
||||
~~~~
|
||||
trait eq {
|
||||
trait Eq {
|
||||
fn equals(&&other: self) -> bool;
|
||||
}
|
||||
|
||||
impl int: eq {
|
||||
impl int: Eq {
|
||||
fn equals(&&other: int) -> bool { other == self }
|
||||
}
|
||||
~~~~
|
||||
@ -1735,14 +1735,14 @@ values of *an* unknown type that conforms to a given trait.
|
||||
However, consider this function:
|
||||
|
||||
~~~~
|
||||
# type circle = int; type rectangle = int;
|
||||
# trait drawable { fn draw(); }
|
||||
# impl int: drawable { fn draw() {} }
|
||||
# type Circle = int; type Rectangle = int;
|
||||
# trait Drawable { fn draw(); }
|
||||
# impl int: Drawable { fn draw() {} }
|
||||
# fn new_circle() -> int { 1 }
|
||||
fn draw_all<T: drawable>(shapes: ~[T]) {
|
||||
fn draw_all<T: Drawable>(shapes: ~[T]) {
|
||||
for shapes.each |shape| { shape.draw(); }
|
||||
}
|
||||
# let c: circle = new_circle();
|
||||
# let c: Circle = new_circle();
|
||||
# draw_all(~[c]);
|
||||
~~~~
|
||||
|
||||
@ -1754,8 +1754,8 @@ When this is needed, a trait name can be used as a type, causing
|
||||
the function to be written simply like this:
|
||||
|
||||
~~~~
|
||||
# trait drawable { fn draw(); }
|
||||
fn draw_all(shapes: ~[drawable]) {
|
||||
# trait Drawable { fn draw(); }
|
||||
fn draw_all(shapes: ~[Drawable]) {
|
||||
for shapes.each |shape| { shape.draw(); }
|
||||
}
|
||||
~~~~
|
||||
@ -1772,15 +1772,15 @@ To construct such a value, you use the `as` operator to cast a value
|
||||
to a trait type:
|
||||
|
||||
~~~~
|
||||
# type circle = int; type rectangle = int;
|
||||
# trait drawable { fn draw(); }
|
||||
# impl int: drawable { fn draw() {} }
|
||||
# type Circle = int; type Rectangle = int;
|
||||
# trait Drawable { fn draw(); }
|
||||
# impl int: Drawable { fn draw() {} }
|
||||
# fn new_circle() -> int { 1 }
|
||||
# fn new_rectangle() -> int { 2 }
|
||||
# fn draw_all(shapes: ~[drawable]) {}
|
||||
let c: circle = new_circle();
|
||||
let r: rectangle = new_rectangle();
|
||||
draw_all(~[c as drawable, r as drawable]);
|
||||
# fn draw_all(shapes: ~[Drawable]) {}
|
||||
let c: Circle = new_circle();
|
||||
let r: Rectangle = new_rectangle();
|
||||
draw_all(~[c as Drawable, r as Drawable]);
|
||||
~~~~
|
||||
|
||||
This will store the value into a box, along with information about the
|
||||
@ -1893,7 +1893,7 @@ It is possible to provide more specific information when using an
|
||||
external crate.
|
||||
|
||||
~~~~ {.ignore}
|
||||
use myfarm (name = "farm", vers = "2.7");
|
||||
extern mod myfarm (name = "farm", vers = "2.7");
|
||||
~~~~
|
||||
|
||||
When a comma-separated list of name/value pairs is given after `use`,
|
||||
@ -1936,8 +1936,7 @@ fn world() -> ~str { ~"world" }
|
||||
|
||||
~~~~ {.ignore}
|
||||
// main.rs
|
||||
extern mod std;
|
||||
use mylib;
|
||||
extern mod mylib;
|
||||
fn main() { io::println(~"hello " + mylib::world()); }
|
||||
~~~~
|
||||
|
||||
@ -1984,9 +1983,9 @@ restricted with `export` directives at the top of the module or file.
|
||||
~~~~
|
||||
mod enc {
|
||||
export encrypt, decrypt;
|
||||
const super_secret_number: int = 10;
|
||||
fn encrypt(n: int) -> int { n + super_secret_number }
|
||||
fn decrypt(n: int) -> int { n - super_secret_number }
|
||||
const SUPER_SECRET_NUMBER: int = 10;
|
||||
fn encrypt(n: int) -> int { n + SUPER_SECRET_NUMBER }
|
||||
fn decrypt(n: int) -> int { n - SUPER_SECRET_NUMBER }
|
||||
}
|
||||
~~~~
|
||||
|
||||
@ -2012,8 +2011,7 @@ fn main() {
|
||||
|
||||
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. This allows us to have a module `core::str`, for example, even
|
||||
though `str` is a built-in type name.
|
||||
modules.
|
||||
|
||||
## Resolution
|
||||
|
||||
@ -2027,10 +2025,10 @@ Identifiers can shadow each other. In this program, `x` is of type
|
||||
`int`:
|
||||
|
||||
~~~~
|
||||
type t = ~str;
|
||||
type MyType = ~str;
|
||||
fn main() {
|
||||
type t = int;
|
||||
let x: t;
|
||||
type MyType = int;
|
||||
let x: MyType;
|
||||
}
|
||||
~~~~
|
||||
|
||||
@ -2038,18 +2036,22 @@ An `use` directive will only import into the namespaces for which
|
||||
identifiers are actually found. Consider this example:
|
||||
|
||||
~~~~
|
||||
type bar = uint;
|
||||
mod foo { fn bar() {} }
|
||||
mod baz {
|
||||
use foo::bar;
|
||||
const x: bar = 20u;
|
||||
fn baz() {
|
||||
let bar = 10u;
|
||||
|
||||
{
|
||||
use foo::bar;
|
||||
let quux = bar;
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
|
||||
When resolving the type name `bar` in the `const` definition, the
|
||||
resolver will first look at the module context for `baz`. This has an
|
||||
import named `bar`, but that's a function, not a type, So it continues
|
||||
to the top level and finds a type named `bar` defined there.
|
||||
When resolving the type name `bar` in the `quux` definition, the
|
||||
resolver will first look at local block context for `baz`. This has an
|
||||
import named `bar`, but that's function, not a value, So it continues
|
||||
to the `baz` function context and finds a value named `bar` defined
|
||||
there.
|
||||
|
||||
Normally, multiple definitions of the same identifier in a scope are
|
||||
disallowed. Local variables defined with `let` are an exception to
|
||||
|
Loading…
x
Reference in New Issue
Block a user