diff options
Diffstat (limited to 'doc/tutorial/func.md')
| -rw-r--r-- | doc/tutorial/func.md | 174 |
1 files changed, 0 insertions, 174 deletions
diff --git a/doc/tutorial/func.md b/doc/tutorial/func.md deleted file mode 100644 index 08744a68dd8..00000000000 --- a/doc/tutorial/func.md +++ /dev/null @@ -1,174 +0,0 @@ -# Functions - -Functions (like all other static declarations, such as `type`) can be -declared both at the top level and inside other functions (or modules, -which we'll come back to in moment). - -The `ret` keyword immediately returns from a function. It is -optionally followed by an expression to return. In functions that -return `()`, the returned expression can be left off. A function can -also return a value by having its top level block produce an -expression (by omitting the final semicolon). - -Some functions (such as the C function `exit`) never return normally. -In Rust, these are annotated with the pseudo-return type '`!`': - - fn dead_end() -> ! { fail; } - -This helps the compiler avoid spurious error messages. For example, -the following code would be a type error if `dead_end` would be -expected to return. - - # fn can_go_left() -> bool { true } - # fn can_go_right() -> bool { true } - # enum dir { left; right; } - # fn dead_end() -> ! { fail; } - let dir = if can_go_left() { left } - else if can_go_right() { right } - else { dead_end(); }; - -## Closures - -Named functions, like those in the previous section, do not close over -their environment. Rust also includes support for closures, which are -functions that can access variables in the scope in which they are -created. - -There are several forms of closures, each with its own role. The most -common type is called a 'block', this is a closure which has full -access to its environment. - - fn call_block_with_ten(b: block(int)) { b(10); } - - let x = 20; - call_block_with_ten({|arg| - #info("x=%d, arg=%d", x, arg); - }); - -This defines a function that accepts a block, and then calls it with a -simple block that executes a log statement, accessing both its -argument and the variable `x` from its environment. - -Blocks can only be used in a restricted way, because it is not allowed -to survive the scope in which it was created. They are allowed to -appear in function argument position and in call position, but nowhere -else. - -### Boxed closures - -When you need to store a closure in a data structure, a block will not -do, since the compiler will refuse to let you store it. For this -purpose, Rust provides a type of closure that has an arbitrary -lifetime, written `fn@` (boxed closure, analogous to the `@` pointer -type described in the next section). - -A boxed closure does not directly access its environment, but merely -copies out the values that it closes over into a private data -structure. This means that it can not assign to these variables, and -will not 'see' updates to them. - -This code creates a closure that adds a given string to its argument, -returns it from a function, and then calls it: - - use std; - - fn mk_appender(suffix: str) -> fn@(str) -> str { - let f = fn@(s: str) -> str { s + suffix }; - ret f; - } - - fn main() { - let shout = mk_appender("!"); - std::io::println(shout("hey ho, let's go")); - } - -### Closure compatibility - -A nice property of Rust closures is that you can pass any kind of -closure (as long as the arguments and return types match) to functions -that expect a `block`. Thus, when writing a higher-order function that -wants to do nothing with its function argument beyond calling it, you -should almost always specify the type of that argument as `block`, so -that callers have the flexibility to pass whatever they want. - - fn call_twice(f: block()) { f(); f(); } - call_twice({|| "I am a block"; }); - call_twice(fn@() { "I am a boxed closure"; }); - fn bare_function() { "I am a plain function"; } - call_twice(bare_function); - -### Unique closures - -<a name="unique"></a> - -Unique closures, written `fn~` in analogy to the `~` pointer type (see -next section), hold on to things that can safely be sent between -processes. They copy the values they close over, much like boxed -closures, but they also 'own' them—meaning no other code can access -them. Unique closures mostly exist to for spawning new -[tasks](task.html). - -### Shorthand syntax - -The compact syntax used for blocks (`{|arg1, arg2| body}`) can also -be used to express boxed and unique closures in situations where the -closure style can be unambiguously derived from the context. Most -notably, when calling a higher-order function you do not have to use -the long-hand syntax for the function you're passing, since the -compiler can look at the argument type to find out what the parameter -types are. - -As a further simplification, if the final parameter to a function is a -closure, the closure need not be placed within parenthesis. You could, -for example, write... - - let doubled = vec::map([1, 2, 3]) {|x| x*2}; - -`vec::map` is a function in the core library that applies its last -argument to every element of a vector, producing a new vector. - -Even when a closure takes no parameters, you must still write the bars -for the parameter list, as in `{|| ...}`. - -## Binding - -Partial application is done using the `bind` keyword in Rust. - - let daynum = bind vec::position(_, ["mo", "tu", "we", "do", - "fr", "sa", "su"]); - -Binding a function produces a boxed closure (`fn@` type) in which some -of the arguments to the bound function have already been provided. -`daynum` will be a function taking a single string argument, and -returning the day of the week that string corresponds to (if any). - -## Iteration - -Functions taking blocks provide a good way to define non-trivial -iteration constructs. For example, this one iterates over a vector -of integers backwards: - - fn for_rev(v: [int], act: block(int)) { - let i = vec::len(v); - while (i > 0u) { - i -= 1u; - act(v[i]); - } - } - -To run such an iteration, you could do this: - - # fn for_rev(v: [int], act: block(int)) {} - for_rev([1, 2, 3], {|n| log(error, n); }); - -Making use of the shorthand where a final closure argument can be -moved outside of the parentheses permits the following, which -looks quite like a normal loop: - - # fn for_rev(v: [int], act: block(int)) {} - for_rev([1, 2, 3]) {|n| - log(error, n); - } - -Note that, because `for_rev()` returns unit type, no semicolon is -needed when the final closure is pulled outside of the parentheses. |
