diff options
Diffstat (limited to 'doc/tutorial/control.md')
| -rw-r--r-- | doc/tutorial/control.md | 200 |
1 files changed, 0 insertions, 200 deletions
diff --git a/doc/tutorial/control.md b/doc/tutorial/control.md deleted file mode 100644 index e13d976aa79..00000000000 --- a/doc/tutorial/control.md +++ /dev/null @@ -1,200 +0,0 @@ -# Control structures - -## Conditionals - -We've seen `if` pass by a few times already. To recap, braces are -compulsory, an optional `else` clause can be appended, and multiple -`if`/`else` constructs can be chained together: - - if false { - std::io::println("that's odd"); - } else if true { - std::io::println("right"); - } else { - std::io::println("neither true nor false"); - } - -The condition given to an `if` construct *must* be of type boolean (no -implicit conversion happens). If the arms return a value, this value -must be of the same type for every arm in which control reaches the -end of the block: - - fn signum(x: int) -> int { - if x < 0 { -1 } - else if x > 0 { 1 } - else { ret 0; } - } - -The `ret` (return) and its semicolon could have been left out without -changing the meaning of this function, but it illustrates that you -will not get a type error in this case, although the last arm doesn't -have type `int`, because control doesn't reach the end of that arm -(`ret` is jumping out of the function). - -## Pattern matching - -Rust's `alt` construct is a generalized, cleaned-up version of C's -`switch` construct. You provide it with a value and a number of arms, -each labelled with a pattern, and it will execute the arm that matches -the value. - - # let my_number = 1; - alt my_number { - 0 { std::io::println("zero"); } - 1 | 2 { std::io::println("one or two"); } - 3 to 10 { std::io::println("three to ten"); } - _ { std::io::println("something else"); } - } - -There is no 'falling through' between arms, as in C—only one arm is -executed, and it doesn't have to explicitly `break` out of the -construct when it is finished. - -The part to the left of each arm is called the pattern. Literals are -valid patterns, and will match only their own value. The pipe operator -(`|`) can be used to assign multiple patterns to a single arm. Ranges -of numeric literal patterns can be expressed with `to`. The underscore -(`_`) is a wildcard pattern that matches everything. - -If the arm with the wildcard pattern was left off in the above -example, running it on a number greater than ten (or negative) would -cause a run-time failure. When no arm matches, `alt` constructs do not -silently fall through—they blow up instead. - -A powerful application of pattern matching is *destructuring*, where -you use the matching to get at the contents of data types. Remember -that `(float, float)` is a tuple of two floats: - - fn angle(vec: (float, float)) -> float { - alt vec { - (0f, y) if y < 0f { 1.5 * float::consts::pi } - (0f, y) { 0.5 * float::consts::pi } - (x, y) { float::atan(y / x) } - } - } - -A variable name in a pattern matches everything, *and* binds that name -to the value of the matched thing inside of the arm block. 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 -elements to a variable. - -Any `alt` arm can have a guard clause (written `if EXPR`), which is -an expression of type `bool` that determines, after the pattern is -found to match, whether the arm is taken or not. The variables bound -by the pattern are available in this guard expression. - -## Destructuring let - -To a limited extent, it is possible to use destructuring patterns when -declaring a variable with `let`. For example, you can say this to -extract the fields from a tuple: - - # fn get_tuple_of_two_ints() -> (int, int) { (1, 1) } - let (a, b) = get_tuple_of_two_ints(); - -This will introduce two new variables, `a` and `b`, bound to the -content of the tuple. - -You may only use irrevocable patterns—patterns that can never fail to -match—in let bindings, though. Things like literals, which only match -a specific value, are not allowed. - -## Loops - -`while` produces a loop that runs as long as its given condition -(which must have type `bool`) evaluates to true. Inside a loop, the -keyword `break` can be used to abort the loop, and `cont` can be used -to abort the current iteration and continue with the next. - - let x = 5; - while true { - x += x - 3; - if x % 5 == 0 { break; } - std::io::println(int::str(x)); - } - -This code prints out a weird sequence of numbers and stops as soon as -it finds one that can be divided by five. - -There's also `while`'s ugly cousin, `do`/`while`, which does not check -its condition on the first iteration, using traditional syntax: - - # fn eat_cake() {} - # fn any_cake_left() -> bool { false } - do { - eat_cake(); - } while any_cake_left(); - -When iterating over a vector, use `for` instead. - - for elt in ["red", "green", "blue"] { - std::io::println(elt); - } - -This will go over each element in the given vector (a three-element -vector of strings, in this case), and repeatedly execute the body with -`elt` bound to the current element. You may add an optional type -declaration (`elt: str`) for the iteration variable if you want. - -For more involved iteration, such as going over the elements of a hash -table, Rust uses higher-order functions. We'll come back to those in a -moment. - -## Failure - -The `fail` keyword causes the current [task][tasks] to fail. You use -it to indicate unexpected failure, much like you'd use `exit(1)` in a -C program, except that in Rust, it is possible for other tasks to -handle the failure, allowing the program to continue running. - -`fail` takes an optional argument, which must have type `str`. Trying -to access a vector out of bounds, or running a pattern match with no -matching clauses, both result in the equivalent of a `fail`. - -[tasks]: task.html - -## Logging - -Rust has a built-in logging mechanism, using the `log` statement. -Logging is polymorphic—any type of value can be logged, and the -runtime will do its best to output a textual representation of the -value. - - log(warn, "hi"); - log(error, (1, [2.5, -1.8])); - -The first argument is the log level (levels `info`, `warn`, and -`error` are predefined), and the second is the value to log. By -default, you *will not* see the output of that first log statement, -which has `warn` level. The environment variable `RUST_LOG` controls -which log level is used. It can contain a comma-separated list of -paths for modules that should be logged. For example, running `rustc` -with `RUST_LOG=rustc::front::attr` will turn on logging in its -attribute parser. If you compile a program named `foo.rs`, its -top-level module will be called `foo`, and you can set `RUST_LOG` to -`foo` to enable `warn` and `info` logging for the module. - -Turned-off `log` statements impose minimal overhead on the code that -contains them, so except in code that needs to be really, really fast, -you should feel free to scatter around debug logging statements, and -leave them in. - -Three macros that combine text-formatting (as with `#fmt`) and logging -are available. These take a string and any number of format arguments, -and will log the formatted string: - - # fn get_error_string() -> str { "boo" } - #warn("only %d seconds remaining", 10); - #error("fatal: %s", get_error_string()); - -## Assertions - -The keyword `assert`, followed by an expression with boolean type, -will check that the given expression results in `true`, and cause a -failure otherwise. It is typically used to double-check things that -*should* hold at a certain point in a program. - - let x = 100; - while (x > 10) { x -= 10; } - assert x == 10; |
