doc: make small corrections to tutorial

This commit is contained in:
Andrew Paseltiner 2012-12-30 16:09:34 -05:00
parent 4be7310be0
commit 4cb9247e3b

View file

@ -80,7 +80,7 @@ supported build environments that are most likely to work.
> "[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 here. Finally, `rustc` may
> need to be [referred to as `rustc.exe`][bug-3319]. It's a bummer, I
> need to be [referred to as `rustc.exe`][bug-3319]. It's a bummer, we
> know.
[bug-3319]: https://github.com/mozilla/rust/issues/3319
@ -114,7 +114,7 @@ for more information on them.
When complete, `make install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
API-documentation tool, `cargo`, the Rust package manager,
API-documentation tool; `cargo`, the Rust package manager;
and `rusti`, the Rust REPL.
[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
@ -181,10 +181,10 @@ in blocks delineated by curly braces; there are control structures
for branching and looping, like the familiar `if` and `while`; function
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;
module names are separated with double-colon, `::`, as with C++.
module names are separated with double-colon (`::`) as with C++.
The main surface difference to be aware of is that the condition at
the head of control structures like `if` and `while` do not require
the head of control structures like `if` and `while` does not require
parentheses, while their bodies *must* be wrapped in
braces. Single-statement, unbraced bodies are not allowed.
@ -226,12 +226,12 @@ let monster_size: int = 50;
~~~~
Local variables may shadow earlier declarations, as in the previous example:
`monster_size` was first declared as a `float`, and then then a second
`monster_size` was declared as an int. If you were to actually compile this
example, though, the compiler will determine that the second `monster_size` is
`monster_size` was first declared as a `float`, and then a second
`monster_size` was declared as an `int`. If you were to actually compile this
example, though, the compiler would determine that the second `monster_size` is
unused and issue a warning (because this situation is likely to indicate a
programmer error). For occasions where unused variables are intentional, their
name may be prefixed with an underscore to silence the warning, like `let
names may be prefixed with an underscore to silence the warning, like `let
_monster_size = 50;`.
Rust identifiers start with an alphabetic
@ -292,7 +292,7 @@ branch has a different value, and `price` gets the value of the branch that
was taken.
In short, everything that's not a declaration (declarations are `let` for
variables, `fn` for functions, and any top-level named items such as
variables; `fn` for functions; and any top-level named items such as
[traits](#traits), [enum types](#enums), and [constants](#constants)) is an
expression, including function bodies.
@ -306,8 +306,8 @@ fn is_four(x: int) -> bool {
## Primitive types and literals
There are general signed and unsigned integer types, `int`, and `uint`,
as well as 8-, 16-, 32-, and 64-bit variations, `i8`, `u16`, etc.
There are general signed and unsigned integer types, `int` and `uint`,
as well as 8-, 16-, 32-, and 64-bit variants, `i8`, `u16`, etc.
Integers can be written in decimal (`144`), hexadecimal (`0x90`), or
binary (`0b10010000`) base. Each integral type has a corresponding literal
suffix that can be used to indicate the type of a literal: `i` for `int`,
@ -326,14 +326,14 @@ let c = 100u; // c is a uint
let d = 1000i32; // d is an i32
~~~~
There are three floating point types, `float`, `f32`, and `f64`.
Floating point numbers are written `0.0`, `1e6`, or `2.1e-4`.
Like integers, floating point literals are inferred to the correct type.
Suffixes `f`, `f32` and `f64` can be used to create literals of a specific type.
There are three floating-point types: `float`, `f32`, and `f64`.
Floating-point numbers are written `0.0`, `1e6`, or `2.1e-4`.
Like integers, floating-point literals are inferred to the correct type.
Suffixes `f`, `f32`, and `f64` can be used to create literals of a specific type.
The keywords `true` and `false` produce literals of type `bool`.
Characters, the `char` type, are 4-byte unicode codepoints,
Characters, the `char` type, are four-byte Unicode codepoints,
whose literals are written between single quotes, as in `'x'`.
Just like C, Rust understands a number of character escapes, using the backslash
character, such as `\n`, `\r`, and `\t`. String literals,
@ -345,8 +345,8 @@ The nil type, written `()`, has a single value, also written `()`.
## Operators
Rust's set of operators contains very few surprises. Arithmetic is done with
`*`, `/`, `%`, `+`, and `-` (multiply, divide, take remainder, add, subtract). `-` is
also a unary prefix operator that negates numbers. As in C, the bit operators
`*`, `/`, `%`, `+`, and `-` (multiply, divide, take remainder, add, and subtract). `-` is
also a unary prefix operator that negates numbers. As in C, the bitwise operators
`>>`, `<<`, `&`, `|`, and `^` are also supported.
Note that, if applied to an integer value, `!` flips all the bits (like `~` in
@ -444,7 +444,7 @@ match my_number {
}
~~~~
Unlike in C, there is no 'falling through' between arms: only one arm
Unlike in C, there is no "falling through" between arms: only one arm
executes, and it doesn't have to explicitly `break` out of the
construct when it is finished.
@ -494,7 +494,7 @@ fn angle(vector: (float, float)) -> float {
A variable name in a pattern matches any value, *and* binds that name
to the value of the matched value inside of the arm's action. Thus, `(0f,
y)` matches any tuple whose first element is zero, and binds `y` to
the second element. `(x, y)` matches any tuple, and binds both
the second element. `(x, y)` matches any two-element tuple, and binds both
elements to variables.
Any `match` arm can have a guard clause (written `if EXPR`), called a
@ -575,7 +575,7 @@ With a value of such a type, you can do `mystack.head += 1`. If `mut` were
omitted from the type, such an assignment would result in a type error.
`match` patterns destructure structs. The basic syntax is
`Name {fieldname: pattern, ...}`:
`Name { fieldname: pattern, ... }`:
~~~~
# struct Point { x: float, y: float }
@ -589,7 +589,7 @@ match mypoint {
In general, the field names of a struct do not have to appear in the same
order they appear in the type. When you are not interested in all
the fields of a struct, a struct pattern may end with `, _` (as in
`Name {field1, _}`) to indicate that you're ignoring all other fields.
`Name { field1, _ }`) to indicate that you're ignoring all other fields.
Additionally, struct fields have a shorthand matching form that simply
reuses the field name as the binding name.
@ -618,15 +618,15 @@ A value of this type is either a `Circle`, in which case it contains a
`Point` struct and a float, or a `Rectangle`, in which case it contains
two `Point` structs. The run-time representation of such a value
includes an identifier of the actual form that it holds, much like the
'tagged union' pattern in C, but with better static guarantees.
"tagged union" pattern in C, but with better static guarantees.
The above declaration will define a type `Shape` that can refer to
such shapes, and two functions, `Circle` and `Rectangle`, which can be
used to construct values of the type (taking arguments of the
specified types). So `Circle(Point {x: 0f, y: 0f}, 10f)` is the way to
specified types). So `Circle(Point { x: 0f, y: 0f }, 10f)` is the way to
create a new circle.
Enum variants need not have type parameters. This `enum` declaration,
Enum variants need not have parameters. This `enum` declaration,
for example, is equivalent to a C enum:
~~~~
@ -659,7 +659,7 @@ variant does not have a discriminator, it defaults to 0. For example,
the value of `North` is 0, `East` is 1, `South` is 2, and `West` is 3.
When an enum is C-like, you can apply the `as` cast operator to
convert it to its discriminator value as an int.
convert it to its discriminator value as an `int`.
<a name="single_variant_enum"></a>
@ -710,7 +710,7 @@ patterns, as in this definition of `area`:
fn area(sh: Shape) -> float {
match sh {
Circle(_, size) => float::consts::pi * size * size,
Rectangle(Point {x, y}, Point {x: x2, y: y2}) => (x2 - x) * (y2 - y)
Rectangle(Point { x, y }, Point { x: x2, y: y2 }) => (x2 - x) * (y2 - y)
}
}
~~~~
@ -721,14 +721,14 @@ introduction form, nullary enum patterns are written without
parentheses.
~~~~
# struct Point {x: float, y: float}
# struct Point { x: float, y: float }
# enum Direction { North, East, South, West }
fn point_from_direction(dir: Direction) -> Point {
match dir {
North => Point {x: 0f, y: 1f},
East => Point {x: 1f, y: 0f},
South => Point {x: 0f, y: -1f},
West => Point {x: -1f, y: 0f}
North => Point { x: 0f, y: 1f },
East => Point { x: 1f, y: 0f },
South => Point { x: 0f, y: -1f },
West => Point { x: -1f, y: 0f }
}
}
~~~~
@ -737,21 +737,22 @@ Enum variants may also be structs. For example:
~~~~
# use core::float;
# struct Point {x: float, y: float}
# struct Point { x: float, y: float }
# fn square(x: float) -> float { x * x }
enum Shape {
Circle { center: Point, radius: float },
Rectangle { top_left: Point, bottom_right: Point }
}
fn area(sh: Shape) -> float {
match sh {
Circle { radius: radius, _ } => float::consts::pi * square(radius),
Rectangle { top_left: top_left, bottom_right: bottom_right } => {
(bottom_right.x - top_left.x) * (bottom_right.y - top_left.y)
}
}
match sh {
Circle { radius: radius, _ } => float::consts::pi * square(radius),
Rectangle { top_left: top_left, bottom_right: bottom_right } => {
(bottom_right.x - top_left.x) * (bottom_right.y - top_left.y)
}
}
}
~~~~
## Tuples
Tuples in Rust behave exactly like structs, except that their fields
@ -800,7 +801,7 @@ fn line(a: int, b: int, x: int) -> int {
The `return` keyword immediately returns from the body of a function. It
is optionally followed by an expression to return. A function can
also return a value by having its top level block produce an
also return a value by having its top-level block produce an
expression.
~~~~
@ -834,7 +835,7 @@ assert () == oops(5, 3, 1);
As with `match` expressions and `let` bindings, function arguments support
pattern destructuring. Like `let`, argument patterns must be irrefutable,
as in this example that unpacks a tuple and returns it.
as in this example that unpacks the first value from a tuple and returns it.
~~~
fn first((value, _): (int, float)) -> int { value }
@ -917,7 +918,7 @@ aggregate types like structs and enums, so as to represent these types
as pointers to heap memory by default. In contrast, Rust, like C and
C++, represents such types directly. Another way to say this is that
aggregate data in Rust are *unboxed*. This means that if you `let x =
Point {x: 1f, y: 1f};`, you are creating a struct on the stack. If you
Point { x: 1f, y: 1f };`, you are creating a struct on the stack. If you
then copy it into a data structure, you copy the entire struct, not
just a pointer.
@ -927,7 +928,7 @@ those with mutable fields, it can be useful to have a single copy on
the stack or on the heap, and refer to that through a pointer.
Rust supports several types of pointers. The safe pointer types are
`@T` for managed boxes allocated on the local heap, `~T`, for
`@T`, for managed boxes allocated on the local heap, `~T`, for
uniquely-owned boxes allocated on the exchange heap, and `&T`, for
borrowed pointers, which may point to any memory, and whose lifetimes
are governed by the call stack.
@ -941,8 +942,8 @@ All pointer types can be dereferenced with the `*` unary operator.
## Managed boxes
Managed boxes are pointers to heap-allocated, garbage collected
memory. Applying the unary `@` operator to an expression creates a
Managed boxes are pointers to heap-allocated, garbage-collected
memory. Applying the unary `@` operator to an expression creates a
managed box. The resulting box contains the result of the
expression. Copying a managed box, as happens during assignment, only
copies a pointer, never the contents of the box.
@ -1037,7 +1038,8 @@ As an example, consider a simple struct type, `Point`:
~~~
struct Point {
x: float, y: float
x: float,
y: float
}
~~~~
@ -1047,9 +1049,9 @@ contains a point, but allocated in a different location:
~~~
# struct Point { x: float, y: float }
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
let managed_box : @Point = @Point {x: 5.0, y: 1.0};
let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};
let on_the_stack : Point = Point { x: 3.0, y: 4.0 };
let managed_box : @Point = @Point { x: 5.0, y: 1.0 };
let owned_box : ~Point = ~Point { x: 7.0, y: 9.0 };
~~~
Suppose we wanted to write a procedure that computed the distance
@ -1078,9 +1080,9 @@ Now we can call `compute_distance()` in various ways:
~~~
# struct Point{ x: float, y: float };
# let on_the_stack : Point = Point {x: 3.0, y: 4.0};
# let managed_box : @Point = @Point {x: 5.0, y: 1.0};
# let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};
# let on_the_stack : Point = Point { x: 3.0, y: 4.0 };
# let managed_box : @Point = @Point { x: 5.0, y: 1.0 };
# let owned_box : ~Point = ~Point { x: 7.0, y: 9.0 };
# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }
compute_distance(&on_the_stack, managed_box);
compute_distance(managed_box, owned_box);
@ -1090,14 +1092,14 @@ Here the `&` operator is used to take the address of the variable
`on_the_stack`; this is because `on_the_stack` has the type `Point`
(that is, a struct value) and we have to take its address to get a
value. We also call this _borrowing_ the local variable
`on_the_stack`, because we are created an alias: that is, another
`on_the_stack`, because we are creating an alias: that is, another
route to the same data.
In the case of the boxes `managed_box` and `owned_box`, however, no
explicit action is necessary. The compiler will automatically convert
a box like `@point` or `~point` to a borrowed pointer like
`&point`. This is another form of borrowing; in this case, the
contents of the managed/owned box is being lent out.
contents of the managed/owned box are being lent out.
Whenever a value is borrowed, there are some limitations on what you
can do with the original. For example, if the contents of a variable
@ -1157,7 +1159,7 @@ let area = (*rect).area();
~~~
To combat this ugliness the dot operator applies _automatic pointer
dereferencing_ to the receiver (the value on the left hand side of the
dereferencing_ to the receiver (the value on the left-hand side of the
dot), so in most cases, explicitly dereferencing the receiver is not necessary.
~~~
@ -1199,7 +1201,7 @@ pointers to vectors are also called 'slices'.
// A fixed-size stack vector
let stack_crayons: [Crayon * 3] = [Almond, AntiqueBrass, Apricot];
// A borrowed pointer to stack allocated vector
// A borrowed pointer to stack-allocated vector
let stack_crayons: &[Crayon] = &[Aquamarine, Asparagus, AtomicTangerine];
// A local heap (managed) vector of crayons
@ -1526,7 +1528,7 @@ do spawn() || {
}
~~~~
Look at all those bars and parentheses - that's two empty argument
Look at all those bars and parentheses -- that's two empty argument
lists back to back. Since that is so unsightly, empty argument lists
may be omitted from `do` expressions.
@ -1605,7 +1607,7 @@ fn contains(v: &[int], elt: int) -> bool {
~~~~
Notice that, because `each` passes each value by borrowed pointer,
the iteratee needs to dereference it before using.
the iteratee needs to dereference it before using it.
In these situations it can be convenient to lean on Rust's
argument patterns to bind `x` to the actual value, not the pointer.
@ -1727,7 +1729,7 @@ s.draw_borrowed();
// ... and dereferenced
(& &s).draw_borrowed();
// ... and dereferenced, and borrowed, and
// ... and dereferenced and borrowed
(&@~s).draw_borrowed();
~~~
@ -1790,9 +1792,9 @@ Inside a generic function, the names of the type parameters
(capitalized by convention) stand for opaque types. All you can do
with instances of these types is pass them around: you can't apply any
operations to them or pattern-match on them. Note that instances of
generic types are often passed by pointer. For example, the parameter
generic types are often passed by pointer. For example, the parameter
`function()` is supplied with a pointer to a value of type `T` and not
a value of type `T` itself. This ensures that the function works with
a value of type `T` itself. This ensures that the function works with
the broadest set of types possible, since some types are expensive or
illegal to copy and pass by value.
@ -1813,7 +1815,7 @@ enum Option<T> {
~~~~
These declarations can be instantiated to valid types like `Set<int>`,
`Stack<int>` and `Option<int>`.
`Stack<int>`, and `Option<int>`.
The last type in that example, `Option`, appears frequently in Rust code.
Because Rust does not have null pointers (except in unsafe code), we need
@ -1822,13 +1824,13 @@ combination of arguments of the appropriate types. The usual way is to write
a function that returns `Option<T>` instead of `T`.
~~~~
# struct Point {x: float, y: float}
# struct Point { x: float, y: float }
# enum Shape { Circle(Point, float), Rectangle(Point, Point) }
fn radius(shape: Shape) -> Option<float> {
match shape {
Circle(_, radius) => Some(radius),
Rectangle(*) => None
}
match shape {
Circle(_, radius) => Some(radius),
Rectangle(*) => None
}
}
~~~~
@ -1892,12 +1894,12 @@ While most traits can be defined and implemented by user code, three
traits are automatically derived and implemented for all applicable
types by the compiler, and may not be overridden:
* `Copy` - Types that can be copied: either implicitly, or explicitly with the
* `Copy` - Types that can be copied, either implicitly, or explicitly with the
`copy` operator. All types are copyable unless they have destructors or
contain types with destructors.
* `Owned` - Owned types. Types are owned unless they contain managed
boxes, managed closures, or borrowed pointers. Owned types may or
boxes, managed closures, or borrowed pointers. Owned types may or
may not be copyable.
* `Const` - Constant (immutable) types. These are types that do not contain
@ -1914,7 +1916,7 @@ garbage collector reclaimed it.
~~~
struct TimeBomb {
explosivity: uint,
explosivity: uint
}
impl TimeBomb : Drop {
@ -2004,12 +2006,12 @@ following trait describes types that support an equality operation:
// In a trait, `self` refers both to the self argument
// and to the type implementing the trait
trait Eq {
fn equals(&self, other: &self) -> bool;
fn equals(&self, other: &self) -> bool;
}
// In an impl, `self` refers just to the value of the receiver
impl int: Eq {
fn equals(&self, other: &int) -> bool { *other == *self }
fn equals(&self, other: &int) -> bool { *other == *self }
}
~~~~
@ -2033,7 +2035,7 @@ impl Circle: Shape {
static fn new(area: float) -> Circle { Circle { radius: sqrt(area / pi) } }
}
impl Square: Shape {
static fn new(area: float) -> Square { Square { length: sqrt(area) } }
static fn new(area: float) -> Square { Square { length: sqrt(area) } }
}
let area = 42.5;
@ -2103,9 +2105,9 @@ fn draw_all<T: Drawable>(shapes: ~[T]) {
# draw_all(~[c]);
~~~~
You can call that on an array of circles, or an array of squares
You can call that on an array of circles, or an array of rectangles
(assuming those have suitable `Drawable` traits defined), but not on
an array containing both circles and squares. When such behavior is
an array containing both circles and rectangles. When such behavior is
needed, a trait name can alternately be used as a type, called
an _object_.
@ -2189,10 +2191,10 @@ Now, we can implement `Circle` on a type only if we also implement `Shape`.
# fn square(x: float) -> float { x * x }
struct CircleStruct { center: Point, radius: float }
impl CircleStruct: Circle {
fn radius(&self) -> float { sqrt(self.area() / pi) }
fn radius(&self) -> float { sqrt(self.area() / pi) }
}
impl CircleStruct: Shape {
fn area(&self) -> float { pi * square(self.radius) }
fn area(&self) -> float { pi * square(self.radius) }
}
~~~~
@ -2266,7 +2268,7 @@ fn chicken_farmer() {
~~~
These farm animal functions have a new keyword, `pub`, attached to
them. The `pub` keyword modifies an item's visibility, making it
them. The `pub` keyword modifies an item's visibility, making it
visible outside its containing module. An expression with `::`, like
`farm::chicken`, can name an item outside of its containing
module. Items, such as those declared with `fn`, `struct`, `enum`,
@ -2276,7 +2278,7 @@ Visibility restrictions in Rust exist only at module boundaries. This
is quite different from most object-oriented languages that also
enforce restrictions on objects themselves. That's not to say that
Rust doesn't support encapsulation: both struct fields and methods can
be private. But this encapsulation is at the module level, not the
be private. But this encapsulation is at the module level, not the
struct level. Note that fields and methods are _public_ by default.
~~~
@ -2320,7 +2322,7 @@ fn main() {
The unit of independent compilation in Rust is the crate: rustc
compiles a single crate at a time, from which it produces either a
library or executable.
library or an executable.
When compiling a single `.rs` source file, the file acts as the whole crate.
You can compile it with the `--lib` compiler switch to create a shared
@ -2368,7 +2370,7 @@ Compiling this file will cause `rustc` to look for files named
`cow.rs`, `chicken.rs`, and `horse.rs` in the same directory as the
`.rc` file, compile them all together, and, based on the presence of
the `crate_type = "lib"` attribute, output a shared library or an
executable. (If the line `#[crate_type = "lib"];` was omitted,
executable. (If the line `#[crate_type = "lib"];` was omitted,
`rustc` would create an executable.)
The `#[link(...)]` attribute provides meta information about the