@@ -1012,67 +1012,90 @@ call_twice(bare_function);
1012
1012
1013
1013
### Do syntax
1014
1014
1015
- Because closures in Rust are frequently used in combination with
1016
- higher-order functions to simulate control structures like `if` and
1017
- `loop`. For example, this one iterates over a vector of integers
1018
- backwards :
1015
+ Closures in Rust are frequently used in combination with higher-order
1016
+ functions to simulate control structures like `if` and
1017
+ `loop`. Consider this function that iterates over a vector of
1018
+ integers, applying an operator to each :
1019
1019
1020
1020
~~~~
1021
- fn for_rev (v: ~[int], act : fn(int)) {
1022
- let mut i = vec::len(v) ;
1023
- while (i > 0u ) {
1024
- i -= 1u ;
1025
- act(v[i]) ;
1026
- }
1021
+ fn each (v: ~[int], op : fn(int)) {
1022
+ let mut n = 0 ;
1023
+ while n < v.len( ) {
1024
+ op(v[n]) ;
1025
+ n += 1 ;
1026
+ }
1027
1027
}
1028
1028
~~~~
1029
1029
1030
- To run such an iteration on a block of code, you could call
1031
- it with a closure containing a block of code.
1030
+ As a caller, if we use a closure to provide the final operator
1031
+ argument, we can write it in a way that has a pleasant, block-like
1032
+ structure.
1032
1033
1033
1034
~~~~
1034
- # fn for_rev (v: ~[int], act : fn(int)) {}
1035
+ # fn each (v: ~[int], op : fn(int)) {}
1035
1036
# fn do_some_work(i: int) { }
1036
- for_rev (~[1, 2, 3], |n| {
1037
+ each (~[1, 2, 3], |n| {
1037
1038
#debug("%i", n);
1038
1039
do_some_work(n);
1039
1040
});
1040
1041
~~~~
1041
1042
1042
- Because this is such a common pattern Rust has a special form
1043
- of function call that can be written more like a built-in control
1044
- structure:
1043
+ This is such a useful pattern that Rust has a special form of function
1044
+ call that can be written more like a built-in control structure:
1045
1045
1046
1046
~~~~
1047
- # fn for_rev (v: [int], act : fn(int)) {}
1047
+ # fn each (v: ~ [int], op : fn(int)) {}
1048
1048
# fn do_some_work(i: int) { }
1049
- do for_rev (~[1, 2, 3]) |n| {
1049
+ do each (~[1, 2, 3]) |n| {
1050
1050
#debug("%i", n);
1051
1051
do_some_work(n);
1052
1052
}
1053
1053
~~~~
1054
1054
1055
- Notice that the call is prefixed with the keyword `do` and, instead of
1056
- writing the final closure inside the argument list it is moved outside
1057
- of the parenthesis where it looks visually more like a typical block
1058
- of code. The `do` expression is purely syntactic sugar for a call
1059
- that takes a final closure argument.
1055
+ The call is prefixed with the keyword `do` and, instead of writing the
1056
+ final closure inside the argument list it is moved outside of the
1057
+ parenthesis where it looks visually more like a typical block of
1058
+ code. The `do` expression is purely syntactic sugar for a call that
1059
+ takes a final closure argument.
1060
+
1061
+ `do` is often used for task spawning.
1062
+
1063
+ ~~~~
1064
+ import task::spawn;
1065
+
1066
+ do spawn() || {
1067
+ #debug("I'm a task, whatever");
1068
+ }
1069
+ ~~~~
1070
+
1071
+ That's nice, but look at all those bars and parentheses - that's two empty
1072
+ argument lists back to back. Wouldn't it be great if they weren't
1073
+ there?
1074
+
1075
+ ~~~~
1076
+ # import task::spawn;
1077
+ do spawn {
1078
+ #debug("Kablam!");
1079
+ }
1080
+ ~~~~
1081
+
1082
+ Empty argument lists can be omitted from `do` expressions.
1060
1083
1061
1084
### For loops
1062
1085
1063
- `for` loops, like `do` expressions, allow functions to be used as
1064
- as control structures. `for` loops can be used to treat functions
1065
- with the proper signature as looping constructs, supporting
1066
- `break`, `cont ` and early returns .
1086
+ Most iteration in Rust is done with `for` loops. Like `do`,
1087
+ `for` is a nice syntax for doing control flow with closures.
1088
+ Additionally, within a `for` loop, `break, `cont`, and `ret`
1089
+ work just as they do with `while ` and `loop` .
1067
1090
1068
- Take for example this `each` function that iterates over a vector,
1069
- breaking early when the iteratee returns `false`:
1091
+ Consider again our `each` function, this time improved to
1092
+ break early when the iteratee returns `false`:
1070
1093
1071
1094
~~~~
1072
- fn each<T> (v: &[T ], f : fn(T ) -> bool) {
1095
+ fn each(v: ~[int ], op : fn(int ) -> bool) {
1073
1096
let mut n = 0;
1074
1097
while n < v.len() {
1075
- if !f (v[n]) {
1098
+ if !op (v[n]) {
1076
1099
break;
1077
1100
}
1078
1101
n += 1;
@@ -1093,10 +1116,11 @@ each(~[2, 4, 8, 5, 16], |n| {
1093
1116
});
1094
1117
~~~~
1095
1118
1096
- You can see how that gets noisy. As a syntactic convenience, if the
1097
- call is preceded by the keyword `for`, the block will implicitly
1098
- return `true`, and `break` and `cont` can be used, much like in a
1099
- `while` loop, to explicitly return `false` or `true`.
1119
+ With `for`, functions like `each` can be treated more
1120
+ like builtin looping structures. When calling `each`
1121
+ in a `for` loop, instead of returning `false` to break
1122
+ out of the loop, you just write `break`. To continue
1123
+ to the next iteration, write `cont`.
1100
1124
1101
1125
~~~~
1102
1126
# import each = vec::each;
@@ -1110,7 +1134,7 @@ for each(~[2, 4, 8, 5, 16]) |n| {
1110
1134
~~~~
1111
1135
1112
1136
As an added bonus, you can use the `ret` keyword, which is not
1113
- normally allowed in blocks , in a block that appears as the body of a
1137
+ normally allowed in closures , in a block that appears as the body of a
1114
1138
`for` loop — this will cause a return to happen from the outer
1115
1139
function, not just the loop body.
1116
1140
@@ -1124,6 +1148,8 @@ fn contains(v: ~[int], elt: int) -> bool {
1124
1148
}
1125
1149
~~~~
1126
1150
1151
+ `for` syntax only works with stack closures.
1152
+
1127
1153
1128
1154
# Datatypes
1129
1155
0 commit comments