2015-01-08 12:27:03 -06:00
|
|
|
|
% Functions
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
Every Rust program has at least one function, the `main` function:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-02-13 09:05:33 -06:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn main() {
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This is the simplest possible function declaration. As we mentioned before,
|
2015-04-10 09:22:44 -05:00
|
|
|
|
`fn` says ‘this is a function’, followed by the name, some parentheses because
|
2014-12-02 08:20:48 -06:00
|
|
|
|
this function takes no arguments, and then some curly braces to indicate the
|
2015-04-10 09:22:44 -05:00
|
|
|
|
body. Here’s a function named `foo`:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-02-13 09:05:33 -06:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn foo() {
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
So, what about taking arguments? Here’s a function that prints a number:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-02-13 09:05:33 -06:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn print_number(x: i32) {
|
|
|
|
|
println!("x is: {}", x);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
Here’s a complete program that uses `print_number`:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-02-13 09:05:33 -06:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn main() {
|
|
|
|
|
print_number(5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn print_number(x: i32) {
|
|
|
|
|
println!("x is: {}", x);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
As you can see, function arguments work very similar to `let` declarations:
|
|
|
|
|
you add a type to the argument name, after a colon.
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
Here’s a complete program that adds two numbers together and prints them:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-02-13 09:05:33 -06:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn main() {
|
|
|
|
|
print_sum(5, 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn print_sum(x: i32, y: i32) {
|
|
|
|
|
println!("sum is: {}", x + y);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
You separate arguments with a comma, both when you call the function, as well
|
|
|
|
|
as when you declare it.
|
|
|
|
|
|
|
|
|
|
Unlike `let`, you _must_ declare the types of function arguments. This does
|
|
|
|
|
not work:
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
```rust,ignore
|
2015-01-10 16:10:00 -06:00
|
|
|
|
fn print_sum(x, y) {
|
2015-02-13 11:09:46 -06:00
|
|
|
|
println!("sum is: {}", x + y);
|
2014-12-02 08:20:48 -06:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
You get this error:
|
|
|
|
|
|
|
|
|
|
```text
|
2015-04-10 09:22:44 -05:00
|
|
|
|
expected one of `!`, `:`, or `@`, found `)`
|
|
|
|
|
fn print_number(x, y) {
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This is a deliberate design decision. While full-program inference is possible,
|
|
|
|
|
languages which have it, like Haskell, often suggest that documenting your
|
|
|
|
|
types explicitly is a best-practice. We agree that forcing functions to declare
|
|
|
|
|
types while allowing for inference inside of function bodies is a wonderful
|
|
|
|
|
sweet spot between full inference and no inference.
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
What about returning a value? Here’s a function that adds one to an integer:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-02-13 09:05:33 -06:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn add_one(x: i32) -> i32 {
|
|
|
|
|
x + 1
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Rust functions return exactly one value, and you declare the type after an
|
2015-04-10 09:22:44 -05:00
|
|
|
|
‘arrow’, which is a dash (`-`) followed by a greater-than sign (`>`). The last
|
|
|
|
|
line of a function determines what it returns. You’ll note the lack of a
|
|
|
|
|
semicolon here. If we added it in:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
```rust,ignore
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn add_one(x: i32) -> i32 {
|
|
|
|
|
x + 1;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
We would get an error:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
error: not all control paths return a value
|
|
|
|
|
fn add_one(x: i32) -> i32 {
|
|
|
|
|
x + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
help: consider removing this semicolon:
|
|
|
|
|
x + 1;
|
|
|
|
|
^
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
This reveals two interesting things about Rust: it is an expression-based
|
|
|
|
|
language, and semicolons are different from semicolons in other ‘curly brace
|
|
|
|
|
and semicolon’-based languages. These two things are related.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
## Expressions vs. Statements
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
Rust is primarily an expression-based language. There are only two kinds of
|
|
|
|
|
statements, and everything else is an expression.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
So what's the difference? Expressions return a value, and statements do not.
|
|
|
|
|
That’s why we end up with ‘not all control paths return a value’ here: the
|
|
|
|
|
statement `x + 1;` doesn’t return a value. There are two kinds of statements in
|
|
|
|
|
Rust: ‘declaration statements’ and ‘expression statements’. Everything else is
|
2015-04-10 09:37:29 -05:00
|
|
|
|
an expression. Let’s talk about declaration statements first.
|
2015-04-10 09:22:44 -05:00
|
|
|
|
|
|
|
|
|
In some languages, variable bindings can be written as expressions, not just
|
|
|
|
|
statements. Like Ruby:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
x = y = 5
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In Rust, however, using `let` to introduce a binding is _not_ an expression. The
|
|
|
|
|
following will produce a compile-time error:
|
|
|
|
|
|
|
|
|
|
```ignore
|
|
|
|
|
let x = (let y = 5); // expected identifier, found keyword `let`
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The compiler is telling us here that it was expecting to see the beginning of
|
|
|
|
|
an expression, and a `let` can only begin a statement, not an expression.
|
|
|
|
|
|
|
|
|
|
Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
|
|
|
|
|
expression, although its value is not particularly useful. Unlike other
|
|
|
|
|
languages where an assignment evaluates to the assigned value (e.g. `5` in the
|
2015-06-10 04:59:36 -05:00
|
|
|
|
previous example), in Rust the value of an assignment is an empty tuple `()`
|
2015-06-10 10:15:24 -05:00
|
|
|
|
because the assigned value can have [just one owner](ownership.html), and any
|
2015-06-10 04:59:36 -05:00
|
|
|
|
other returned value would be too surprising:
|
2015-04-10 09:22:44 -05:00
|
|
|
|
|
2015-05-18 13:56:00 -05:00
|
|
|
|
```rust
|
2015-04-10 09:22:44 -05:00
|
|
|
|
let mut y = 5;
|
|
|
|
|
|
|
|
|
|
let x = (y = 6); // x has the value `()`, not `6`
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The second kind of statement in Rust is the *expression statement*. Its
|
|
|
|
|
purpose is to turn any expression into a statement. In practical terms, Rust's
|
|
|
|
|
grammar expects statements to follow other statements. This means that you use
|
|
|
|
|
semicolons to separate expressions from each other. This means that Rust
|
|
|
|
|
looks a lot like most other languages that require you to use semicolons
|
|
|
|
|
at the end of every line, and you will see semicolons at the end of almost
|
|
|
|
|
every line of Rust code you see.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
What is this exception that makes us say "almost"? You saw it already, in this
|
|
|
|
|
code:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn add_one(x: i32) -> i32 {
|
2014-12-02 08:20:48 -06:00
|
|
|
|
x + 1
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
Our function claims to return an `i32`, but with a semicolon, it would return
|
|
|
|
|
`()` instead. Rust realizes this probably isn’t what we want, and suggests
|
|
|
|
|
removing the semicolon in the error we saw before.
|
|
|
|
|
|
|
|
|
|
## Early returns
|
|
|
|
|
|
|
|
|
|
But what about early returns? Rust does have a keyword for that, `return`:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-02-13 09:05:33 -06:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn foo(x: i32) -> i32 {
|
2015-04-10 09:22:44 -05:00
|
|
|
|
return x;
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
// we never run this code!
|
|
|
|
|
x + 1
|
2014-12-02 08:20:48 -06:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
Using a `return` as the last line of a function works, but is considered poor
|
|
|
|
|
style:
|
2015-01-15 13:47:21 -06:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn foo(x: i32) -> i32 {
|
2015-04-10 09:22:44 -05:00
|
|
|
|
return x + 1;
|
2015-01-15 13:47:21 -06:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
The previous definition without `return` may look a bit strange if you haven’t
|
|
|
|
|
worked in an expression-based language before, but it becomes intuitive over
|
|
|
|
|
time.
|
2015-01-15 13:47:21 -06:00
|
|
|
|
|
2015-02-13 09:05:33 -06:00
|
|
|
|
## Diverging functions
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
Rust has some special syntax for ‘diverging functions’, which are functions that
|
2015-02-13 09:05:33 -06:00
|
|
|
|
do not return:
|
|
|
|
|
|
2015-05-18 13:56:00 -05:00
|
|
|
|
```rust
|
2015-02-13 09:05:33 -06:00
|
|
|
|
fn diverges() -> ! {
|
|
|
|
|
panic!("This function never returns!");
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-10 09:22:44 -05:00
|
|
|
|
`panic!` is a macro, similar to `println!()` that we’ve already seen. Unlike
|
2015-02-13 09:05:33 -06:00
|
|
|
|
`println!()`, `panic!()` causes the current thread of execution to crash with
|
2015-08-18 12:42:34 -05:00
|
|
|
|
the given message. Because this function will cause a crash, it will never
|
|
|
|
|
return, and so it has the type ‘`!`’, which is read ‘diverges’.
|
2015-02-13 09:05:33 -06:00
|
|
|
|
|
2015-08-18 12:42:34 -05:00
|
|
|
|
If you add a main function that calls `diverges()` and run it, you’ll get
|
|
|
|
|
some output that looks like this:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
thread ‘<main>’ panicked at ‘This function never returns!’, hello.rs:2
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If you want more information, you can get a backtrace by setting the
|
|
|
|
|
`RUST_BACKTRACE` environment variable:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
$ RUST_BACKTRACE=1 ./diverges
|
|
|
|
|
thread '<main>' panicked at 'This function never returns!', hello.rs:2
|
|
|
|
|
stack backtrace:
|
|
|
|
|
1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
|
|
|
|
|
2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
|
|
|
|
|
3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw
|
|
|
|
|
4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650
|
|
|
|
|
5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa
|
|
|
|
|
6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa
|
|
|
|
|
7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231
|
|
|
|
|
8: 0x7f402773d1d8 - __rust_try
|
|
|
|
|
9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w
|
|
|
|
|
10: 0x7f4027738a19 - main
|
|
|
|
|
11: 0x7f402694ab44 - __libc_start_main
|
|
|
|
|
12: 0x7f40277386c8 - <unknown>
|
|
|
|
|
13: 0x0 - <unknown>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`RUST_BACKTRACE` also works with Cargo’s `run` command:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
$ RUST_BACKTRACE=1 cargo run
|
|
|
|
|
Running `target/debug/diverges`
|
|
|
|
|
thread '<main>' panicked at 'This function never returns!', hello.rs:2
|
|
|
|
|
stack backtrace:
|
|
|
|
|
1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
|
|
|
|
|
2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
|
|
|
|
|
3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw
|
|
|
|
|
4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650
|
|
|
|
|
5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa
|
|
|
|
|
6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa
|
|
|
|
|
7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231
|
|
|
|
|
8: 0x7f402773d1d8 - __rust_try
|
|
|
|
|
9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w
|
|
|
|
|
10: 0x7f4027738a19 - main
|
|
|
|
|
11: 0x7f402694ab44 - __libc_start_main
|
|
|
|
|
12: 0x7f40277386c8 - <unknown>
|
|
|
|
|
13: 0x0 - <unknown>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
A diverging function can be used as any type:
|
2015-02-13 09:05:33 -06:00
|
|
|
|
|
2015-03-18 16:34:40 -05:00
|
|
|
|
```should_panic
|
2015-02-13 09:05:33 -06:00
|
|
|
|
# fn diverges() -> ! {
|
|
|
|
|
# panic!("This function never returns!");
|
|
|
|
|
# }
|
|
|
|
|
let x: i32 = diverges();
|
|
|
|
|
let x: String = diverges();
|
|
|
|
|
```
|
2015-08-05 12:44:54 -05:00
|
|
|
|
|
|
|
|
|
## Function pointers
|
|
|
|
|
|
|
|
|
|
We can also create variable bindings which point to functions:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
let f: fn(i32) -> i32;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`f` is a variable binding which points to a function that takes an `i32` as
|
|
|
|
|
an argument and returns an `i32`. For example:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn plus_one(i: i32) -> i32 {
|
|
|
|
|
i + 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// without type inference
|
|
|
|
|
let f: fn(i32) -> i32 = plus_one;
|
|
|
|
|
|
|
|
|
|
// with type inference
|
|
|
|
|
let f = plus_one;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
We can then use `f` to call the function:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
# fn plus_one(i: i32) -> i32 { i + 1 }
|
|
|
|
|
# let f = plus_one;
|
|
|
|
|
let six = f(5);
|
|
|
|
|
```
|