Skip to content

Commit 43def06

Browse files
committed
tutorial: More updates for closures
1 parent 47f43da commit 43def06

File tree

2 files changed

+72
-47
lines changed

2 files changed

+72
-47
lines changed

doc/tutorial.md

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -495,16 +495,10 @@ let s = "a\
495495
496496
## Operators
497497
498-
Rust's set of operators contains very few surprises. The main
499-
difference with C is that `++` and `--` are missing, and that the
500-
logical bitwise operators have higher precedence—in C, `x & 2 > 0`
501-
comes out as `x & (2 > 0)`, in Rust, it means `(x & 2) > 0`, which is
502-
more likely to be what you expect (unless you are a C veteran).
503-
504-
Thus, binary arithmetic is done with `*`, `/`, `%`, `+`, and `-`
505-
(multiply, divide, remainder, plus, minus). `-` is also a unary prefix
506-
operator (there are no unary postfix operators in Rust) that does
507-
negation.
498+
Rust's set of operators contains very few surprises. Binary arithmetic
499+
is done with `*`, `/`, `%`, `+`, and `-` (multiply, divide, remainder,
500+
plus, minus). `-` is also a unary prefix operator (there are no unary
501+
postfix operators in Rust) that does negation.
508502
509503
Binary shifting is done with `>>` (shift right), and `<<` (shift
510504
left). Shift right is arithmetic if the value is signed and logical if
@@ -528,6 +522,11 @@ let y: uint = x as uint;
528522
assert y == 4u;
529523
~~~~
530524
525+
The main difference with C is that `++` and `--` are missing, and that
526+
the logical bitwise operators have higher precedence — in C, `x & 2 > 0`
527+
comes out as `x & (2 > 0)`, in Rust, it means `(x & 2) > 0`, which is
528+
more likely to be what you expect (unless you are a C veteran).
529+
531530
## Attributes
532531
533532
Every definition can be annotated with attributes. Attributes are meta
@@ -850,33 +849,32 @@ fn bar() -> int {
850849
}
851850
~~~~
852851
853-
Rust also supports _closures_, functions that can
854-
access variables in the enclosing scope.
852+
Rust also supports _closures_, functions that can access variables in
853+
the enclosing scope.
855854
856855
~~~~
856+
# import println = io::println;
857857
fn call_closure_with_ten(b: fn(int)) { b(10); }
858858
859-
let x = 20;
860-
let closure = |arg| #info("x=%d, arg=%d", x, arg);
859+
let captured_var = 20;
860+
let closure = |arg| println(#fmt("captured_var=%d, arg=%d", captured_var, arg));
861861
862862
call_closure_with_ten(closure);
863863
~~~~
864864
865-
A closure is defined by listing the arguments, between bars, followed
866-
by an expression that acts as the function body. The types of the
867-
arguments are generally omitted, as is the return type, because
868-
the compiler can almost always infer them. In the rare case where
869-
the compiler needs assistance though, the arguments and return
870-
types may be annotated.
865+
The types of the arguments are generally omitted, as is the return
866+
type, because the compiler can almost always infer them. In the rare
867+
case where the compiler needs assistance though, the arguments and
868+
return types may be annotated.
871869
872870
~~~~
873871
# type mygoodness = fn(str) -> str; type what_the = int;
874872
let bloop = |well, oh: mygoodness| -> what_the { fail oh(well) };
875873
~~~~
876874
877875
There are several forms of closure, each with its own role. The most
878-
common, called a _stack closure_ and written `&fn()` has direct access
879-
to local variables in the enclosing scope.
876+
common, called a _stack closure_, has type `fn&` and can directly
877+
access local variables in the enclosing scope.
880878
881879
~~~~
882880
let mut max = 0;
@@ -888,10 +886,9 @@ allocated on the call stack and refers by pointer to captured
888886
locals. To ensure that stack closures never outlive the local
889887
variables to which they refer, they can only be used in argument
890888
position and cannot be stored in structures nor returned from
891-
functions. Despite the usage limitations stack closures are used
889+
functions. Despite the usage limitations stack closures are used
892890
pervasively in Rust code.
893891
894-
895892
### Boxed closures
896893
897894
When you need to store a closure in a data structure, a stack closure
@@ -922,6 +919,19 @@ fn main() {
922919
}
923920
~~~~
924921
922+
This example uses the long closure syntax, `fn@(s: str) ...`,
923+
making the fact that we are declaring a box closure explicit. In
924+
practice boxed closures are usually defined with the short closure
925+
syntax introduced earlier, in which case the compiler will infer
926+
the type of closure. Thus our boxed closure example could also
927+
be written:
928+
929+
~~~~
930+
fn mk_appender(suffix: str) -> fn@(str) -> str {
931+
ret |s| s + suffix;
932+
}
933+
~~~~
934+
925935
### Closure compatibility
926936
927937
A nice property of Rust closures is that you can pass any kind of
@@ -946,18 +956,11 @@ Unique closures, written `fn~` in analogy to the `~` pointer type (see
946956
next section), hold on to things that can safely be sent between
947957
processes. They copy the values they close over, much like boxed
948958
closures, but they also 'own' them—meaning no other code can access
949-
them. Unique closures mostly exist for spawning new [tasks](#tasks).
959+
them. Unique closures are used in concurrent code, particularly
960+
for spawning [tasks](#tasks).
950961
951962
### Do syntax
952963
953-
The compact syntax used for stack closures (`|arg1, arg2| body`) can
954-
also be used to express boxed and unique closures in situations where
955-
the closure style can be unambiguously derived from the context. Most
956-
notably, when calling a higher-order function you do not have to use
957-
the long-hand syntax for the function you're passing, since the
958-
compiler can look at the argument type to find out what the parameter
959-
types are.
960-
961964
Because closures in Rust are so versatile, they are used often, and in
962965
particular, functions taking closures are used as control structures
963966
in much the same way as `if` or `loop`. For example, this one iterates
@@ -997,16 +1000,36 @@ of the parenthesis where it looks visually more like a typical block
9971000
of code. The `do` expression is purely syntactic sugar for a call
9981001
that takes a final closure argument.
9991002
1000-
# For loops
1003+
### For loops
10011004
1002-
To allow breaking out of loops, many iteration functions, such as
1003-
`vec::each`, take a function that returns a boolean, and can return
1004-
`false` to break off iteration.
1005+
`for` loops, like `do` expressions, allow functions to be used as
1006+
as control structures. `for` loops can be used to treat functions
1007+
with the proper signature as looping constructs, supporting
1008+
`break`, `cont` and early returns.
10051009
1010+
Take for example this `each` function that iterates over a vector,
1011+
breaking early when the iteratee returns `false`:
1012+
1013+
~~~~
1014+
fn each<T>(v: &[T], f: fn(T) -> bool) {
1015+
let mut n = 0;
1016+
while n < v.len() {
1017+
if !f(v[n]) {
1018+
break;
1019+
}
1020+
n += 1;
1021+
}
1022+
}
10061023
~~~~
1007-
vec::each(~[2, 4, 8, 5, 16], |n| {
1024+
1025+
And using this function to iterate over a vector:
1026+
1027+
~~~~
1028+
# import each = vec::each;
1029+
# import println = io::println;
1030+
each(~[2, 4, 8, 5, 16], |n| {
10081031
if n % 2 != 0 {
1009-
io::println("found odd number!");
1032+
println("found odd number!");
10101033
false
10111034
} else { true }
10121035
});
@@ -1018,9 +1041,11 @@ return `true`, and `break` and `cont` can be used, much like in a
10181041
`while` loop, to explicitly return `false` or `true`.
10191042
10201043
~~~~
1021-
for vec::each(~[2, 4, 8, 5, 16]) |n| {
1044+
# import each = vec::each;
1045+
# import println = io::println;
1046+
for each(~[2, 4, 8, 5, 16]) |n| {
10221047
if n % 2 != 0 {
1023-
io::println("found odd number!");
1048+
println("found odd number!");
10241049
break;
10251050
}
10261051
}
@@ -1032,14 +1057,16 @@ normally allowed in blocks, in a block that appears as the body of a
10321057
function, not just the loop body.
10331058
10341059
~~~~
1060+
# import each = vec::each;
10351061
fn contains(v: ~[int], elt: int) -> bool {
1036-
for vec::each(v) |x| {
1062+
for each(v) |x| {
10371063
if (x == elt) { ret true; }
10381064
}
10391065
false
10401066
}
10411067
~~~~
10421068
1069+
10431070
# Datatypes
10441071
10451072
Rust datatypes are, by default, immutable. The core datatypes of Rust
@@ -2579,6 +2606,8 @@ fn divide(a: float, b: float) -> float {
25792606
#[test]
25802607
#[should_fail]
25812608
fn divide_by_zero() { divide(1f, 0f); }
2609+
2610+
# fn main() { }
25822611
~~~~
25832612
25842613
To disable a test completely, add an `#[ignore]` attribute. Running a

src/etc/extract-tests.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,7 @@
5050
block += re.sub("^# ", "", line)
5151
if not ignore:
5252
if not re.search(r"\bfn main\b", block):
53-
if re.search(
54-
r"(^|\n) *(native|use|mod|import|export)\b", block):
55-
block += "\nfn main() {}\n"
56-
else:
57-
block = "fn main() {\n" + block + "\n}\n"
53+
block = "fn main() {\n" + block + "\n}\n"
5854
if not re.search(r"\buse std\b", block):
5955
block = "use std;\n" + block;
6056
if xfail:

0 commit comments

Comments
 (0)