Copyedit section 3 of tutorial
This commit is contained in:
parent
38ccaed4ce
commit
6627ac6623
@ -184,8 +184,8 @@ and mostly have the same precedence as in C; comments are again like C.
|
|||||||
|
|
||||||
The main surface difference to be aware of is that the condition at
|
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` do not require
|
||||||
paretheses, while their bodies *must* be wrapped in
|
parentheses, while their bodies *must* be wrapped in
|
||||||
brackets. Single-statement, bracket-less bodies are not allowed.
|
braces. Single-statement, unbraced bodies are not allowed.
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# fn recalibrate_universe() -> bool { true }
|
# fn recalibrate_universe() -> bool { true }
|
||||||
@ -200,9 +200,9 @@ fn main() {
|
|||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The `let` keyword introduces a local variable. Variables are immutable
|
The `let` keyword introduces a local variable. Variables are immutable by
|
||||||
by default, so `let mut` can be used to introduce a local variable
|
default. To introduce a local variable that you can re-assign later, use `let
|
||||||
that can be reassigned.
|
mut` instead.
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
let hi = "hi";
|
let hi = "hi";
|
||||||
@ -224,14 +224,14 @@ let imaginary_size = monster_size * 10.0;
|
|||||||
let monster_size: int = 50;
|
let monster_size: int = 50;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Local variables may shadow earlier declarations, as in the previous
|
Local variables may shadow earlier declarations, as in the previous example:
|
||||||
example in which `monster_size` is first declared as a `float`
|
`monster_size` was first declared as a `float`, and then then a second
|
||||||
then a second `monster_size` is declared as an int. If you were to actually
|
`monster_size` was declared as an int. If you were to actually compile this
|
||||||
compile this example though, the compiler will see that the second
|
example, though, the compiler will determine that the second `monster_size` is
|
||||||
`monster_size` is unused, assume that you have made a mistake, and issue
|
unused and issue a warning (because this situation is likely to indicate a
|
||||||
a warning. For occasions where unused variables are intentional, their
|
programmer error). For occasions where unused variables are intentional, their
|
||||||
name may be prefixed with an underscore to silence the warning, like
|
name may be prefixed with an underscore to silence the warning, like `let
|
||||||
`let _monster_size = 50;`.
|
_monster_size = 50;`.
|
||||||
|
|
||||||
Rust identifiers follow the same rules as C; they start with an alphabetic
|
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
|
character or an underscore, and after that may contain any sequence of
|
||||||
@ -278,10 +278,10 @@ let price =
|
|||||||
};
|
};
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Both pieces of code are exactly equivalent—they assign a value to
|
Both pieces of code are exactly equivalent: they assign a value to
|
||||||
`price` depending on the condition that holds. Note that there
|
`price` depending on the condition that holds. Note that there
|
||||||
are not semicolons in the blocks of the second snippet. This is
|
are no semicolons in the blocks of the second snippet. This is
|
||||||
important; the lack of a semicolon after the last statement in a
|
important: the lack of a semicolon after the last statement in a
|
||||||
braced block gives the whole block the value of that last 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*.
|
||||||
@ -290,8 +290,10 @@ would simply assign `()` (nil or void) to `price`. But without the semicolon, ea
|
|||||||
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.
|
||||||
|
|
||||||
In short, everything that's not a declaration (`let` for variables,
|
In short, everything that's not a declaration (declarations are `let` for
|
||||||
`fn` for functions, et cetera) is an expression, including function bodies.
|
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.
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
fn is_four(x: int) -> bool {
|
fn is_four(x: int) -> bool {
|
||||||
@ -314,7 +316,7 @@ 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 semicolon-terminated;
|
||||||
let x = foo();
|
let x = foo();
|
||||||
|
|
||||||
// When used in statement position, bracy expressions do not
|
// When used in statement position, bracy expressions do not
|
||||||
@ -346,7 +348,7 @@ This may sound intricate, but it is super-useful and will grow on you.
|
|||||||
The basic types include the usual boolean, integral, and floating-point types.
|
The basic types include the usual boolean, integral, and floating-point types.
|
||||||
|
|
||||||
------------------------- -----------------------------------------------
|
------------------------- -----------------------------------------------
|
||||||
`()` Nil, the type that has only a single value
|
`()` Unit, the type that has only a single value
|
||||||
`bool` Boolean type, with values `true` and `false`
|
`bool` Boolean type, with values `true` and `false`
|
||||||
`int`, `uint` Machine-pointer-sized signed and unsigned integers
|
`int`, `uint` Machine-pointer-sized signed and unsigned integers
|
||||||
`i8`, `i16`, `i32`, `i64` Signed integers with a specific size (in bits)
|
`i8`, `i16`, `i32`, `i64` Signed integers with a specific size (in bits)
|
||||||
@ -394,10 +396,15 @@ type MonsterSize = uint;
|
|||||||
This will provide a synonym, `MonsterSize`, for unsigned integers. It will not
|
This will provide a synonym, `MonsterSize`, for unsigned integers. It will not
|
||||||
actually create a new, incompatible type—`MonsterSize` and `uint` can be used
|
actually create a new, incompatible type—`MonsterSize` and `uint` can be used
|
||||||
interchangeably, and using one where the other is expected is not a type
|
interchangeably, and using one where the other is expected is not a type
|
||||||
error.
|
error. In that sense, types declared with `type` are *structural*: their
|
||||||
|
meaning follows from their structure, and their names are irrelevant in the
|
||||||
|
type system.
|
||||||
|
|
||||||
To create data types which are not synonyms, `struct` and `enum`
|
Sometimes, you want your data types to be *nominal* instead of structural: you
|
||||||
can be used. They're described in more detail below, but they look like this:
|
want their name to be part of their meaning, so that types with the same
|
||||||
|
structure but different names are not interchangeable. Rust has two ways to
|
||||||
|
create nominal data types: `struct` and `enum`. They're described in more
|
||||||
|
detail below, but they look like this:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
enum HidingPlaces {
|
enum HidingPlaces {
|
||||||
@ -416,12 +423,12 @@ enum MonsterSize = uint; // a single-variant enum
|
|||||||
|
|
||||||
## Literals
|
## Literals
|
||||||
|
|
||||||
Integers can be written in decimal (`144`), hexadecimal (`0x90`), and
|
Integers can be written in decimal (`144`), hexadecimal (`0x90`), or
|
||||||
binary (`0b10010000`) base. Each integral type has a corresponding literal
|
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`,
|
suffix that can be used to indicate the type of a literal: `i` for `int`,
|
||||||
`u` for `uint`, and `i8` for the `i8` type, etc.
|
`u` for `uint`, and `i8` for the `i8` type, etc.
|
||||||
|
|
||||||
In the absense of an integer literal suffix, Rust will infer the
|
In the absence of an integer literal suffix, Rust will infer the
|
||||||
integer type based on type annotations and function signatures in the
|
integer type based on type annotations and function signatures in the
|
||||||
surrounding program. In the absence of any type information at all,
|
surrounding program. In the absence of any type information at all,
|
||||||
Rust will assume that an unsuffixed integer literal has type
|
Rust will assume that an unsuffixed integer literal has type
|
||||||
@ -439,10 +446,10 @@ a suffix, the literal is assumed to be of type `float`. Suffixes `f32`
|
|||||||
(32-bit) and `f64` (64-bit) can be used to create literals of a
|
(32-bit) and `f64` (64-bit) can be used to create literals of a
|
||||||
specific type.
|
specific type.
|
||||||
|
|
||||||
The nil literal is written just like the type: `()`. The keywords
|
The unit literal is written just like the type: `()`. The keywords
|
||||||
`true` and `false` produce the boolean literals.
|
`true` and `false` produce the boolean literals.
|
||||||
|
|
||||||
Character literals are written between single quotes, as in `'x'`. Just as in
|
Character literals are written between single quotes, as in `'x'`. Just like
|
||||||
C, Rust understands a number of character escapes, using the backslash
|
C, Rust understands a number of character escapes, using the backslash
|
||||||
character, such as `\n`, `\r`, and `\t`. String literals,
|
character, such as `\n`, `\r`, and `\t`. String literals,
|
||||||
written between double quotes, allow the same escape sequences. Rust strings
|
written between double quotes, allow the same escape sequences. Rust strings
|
||||||
@ -450,13 +457,13 @@ may contain newlines.
|
|||||||
|
|
||||||
## Constants
|
## Constants
|
||||||
|
|
||||||
Compile-time constants are declared with `const`. All scalar types,
|
Compile-time constants are declared with `const`. A constant may have any
|
||||||
like integers and floats, may be declared `const`, as well as fixed
|
scalar type (for example, integer or float). Other allowable constant types
|
||||||
length vectors, static strings (more on this later), and structs.
|
are fixed-length vectors, static strings (more on this later), and
|
||||||
Constants may be declared in any scope and may refer to other
|
structs. Constants may be declared in any scope and may refer to other
|
||||||
constants. Constant declarations are not type inferred, so must always
|
constants. The compiler does not infer types for constants, so constants must
|
||||||
have a type annotation. By convention they are written in all capital
|
always be declared with a type annotation. By convention, they are written in
|
||||||
letters.
|
all capital letters.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
// Scalars can be constants
|
// Scalars can be constants
|
||||||
@ -480,7 +487,7 @@ const MY_STRUCTY_PASSWORD: Password = Password { value: MY_PASSWORD };
|
|||||||
|
|
||||||
Rust's set of operators contains very few surprises. Arithmetic is done with
|
Rust's set of operators contains very few surprises. Arithmetic is done with
|
||||||
`*`, `/`, `%`, `+`, and `-` (multiply, divide, remainder, plus, minus). `-` is
|
`*`, `/`, `%`, `+`, and `-` (multiply, divide, remainder, plus, minus). `-` is
|
||||||
also a unary prefix operator that does negation. As in C, the bit operators
|
also a unary prefix operator that negates numbers. As in C, the bit operators
|
||||||
`>>`, `<<`, `&`, `|`, and `^` are also supported.
|
`>>`, `<<`, `&`, `|`, and `^` are also supported.
|
||||||
|
|
||||||
Note that, if applied to an integer value, `!` flips all the bits (like `~` in
|
Note that, if applied to an integer value, `!` flips all the bits (like `~` in
|
||||||
@ -502,21 +509,21 @@ assert y == 4u;
|
|||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The main difference with C is that `++` and `--` are missing, and that
|
The main difference with C is that `++` and `--` are missing, and that
|
||||||
the logical bitwise operators have higher precedence — in C, `x & 2 > 0`
|
the logical bitwise operators have higher precedence—in C, `x & 2 > 0`
|
||||||
means `x & (2 > 0)`, but in Rust, it means `(x & 2) > 0`, which is
|
means `x & (2 > 0)`, but in Rust, it means `(x & 2) > 0`, which is
|
||||||
more likely what a novice expects.
|
more likely to be what a novice expects.
|
||||||
|
|
||||||
## Syntax extensions
|
## Syntax extensions
|
||||||
|
|
||||||
*Syntax extensions* are special forms that are not built into the language,
|
*Syntax extensions* are special forms that are not built into the language,
|
||||||
but are instead provided by the libraries. To make it clear to the reader when
|
but are instead provided by the libraries. To make it clear to the reader when
|
||||||
a syntax extension is being used, the names of all syntax extensions end with
|
a name refers to a syntax extension, the names of all syntax extensions end
|
||||||
`!`. The standard library defines a few syntax extensions, the most useful of
|
with `!`. The standard library defines a few syntax extensions, the most
|
||||||
which is `fmt!`, a `sprintf`-style text formatter that is expanded at compile
|
useful of which is `fmt!`, a `sprintf`-style text formatter that an early
|
||||||
time.
|
compiler phase expands statically.
|
||||||
|
|
||||||
`fmt!` supports most of the directives that [printf][pf] supports, but
|
`fmt!` supports most of the directives that [printf][pf] supports, but unlike
|
||||||
will give you a compile-time error when the types of the directives
|
printf, will give you a compile-time error when the types of the directives
|
||||||
don't match the types of the arguments.
|
don't match the types of the arguments.
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
@ -530,8 +537,9 @@ io::println(fmt!("what is this thing: %?", mystery_object));
|
|||||||
|
|
||||||
[pf]: http://en.cppreference.com/w/cpp/io/c/fprintf
|
[pf]: http://en.cppreference.com/w/cpp/io/c/fprintf
|
||||||
|
|
||||||
You can define your own syntax extensions with the macro system, which is out
|
You can define your own syntax extensions with the macro system. For details, see the [macro tutorial][macros].
|
||||||
of scope of this tutorial.
|
|
||||||
|
[macros]: tutorial-macros.html
|
||||||
|
|
||||||
# Control structures
|
# Control structures
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user