]> git.proxmox.com Git - rustc.git/blame - src/doc/book/functions.md
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / doc / book / functions.md
CommitLineData
1a4d82fc
JJ
1% Functions
2
9346a6ac 3Every Rust program has at least one function, the `main` function:
1a4d82fc 4
85aaf69f 5```rust
1a4d82fc
JJ
6fn main() {
7}
8```
9
10This is the simplest possible function declaration. As we mentioned before,
9346a6ac 11`fn` says ‘this is a function’, followed by the name, some parentheses because
1a4d82fc 12this function takes no arguments, and then some curly braces to indicate the
9346a6ac 13body. Here’s a function named `foo`:
1a4d82fc 14
85aaf69f 15```rust
1a4d82fc
JJ
16fn foo() {
17}
18```
19
9346a6ac 20So, what about taking arguments? Here’s a function that prints a number:
1a4d82fc 21
85aaf69f 22```rust
1a4d82fc
JJ
23fn print_number(x: i32) {
24 println!("x is: {}", x);
25}
26```
27
9346a6ac 28Here’s a complete program that uses `print_number`:
1a4d82fc 29
85aaf69f 30```rust
1a4d82fc
JJ
31fn main() {
32 print_number(5);
33}
34
35fn print_number(x: i32) {
36 println!("x is: {}", x);
37}
38```
39
40As you can see, function arguments work very similar to `let` declarations:
41you add a type to the argument name, after a colon.
42
9346a6ac 43Here’s a complete program that adds two numbers together and prints them:
1a4d82fc 44
85aaf69f 45```rust
1a4d82fc
JJ
46fn main() {
47 print_sum(5, 6);
48}
49
50fn print_sum(x: i32, y: i32) {
51 println!("sum is: {}", x + y);
52}
53```
54
55You separate arguments with a comma, both when you call the function, as well
56as when you declare it.
57
58Unlike `let`, you _must_ declare the types of function arguments. This does
59not work:
60
9346a6ac 61```rust,ignore
85aaf69f
SL
62fn print_sum(x, y) {
63 println!("sum is: {}", x + y);
1a4d82fc
JJ
64}
65```
66
67You get this error:
68
69```text
9346a6ac 70expected one of `!`, `:`, or `@`, found `)`
7453a54e 71fn print_sum(x, y) {
1a4d82fc
JJ
72```
73
74This is a deliberate design decision. While full-program inference is possible,
75languages which have it, like Haskell, often suggest that documenting your
76types explicitly is a best-practice. We agree that forcing functions to declare
77types while allowing for inference inside of function bodies is a wonderful
78sweet spot between full inference and no inference.
79
9346a6ac 80What about returning a value? Here’s a function that adds one to an integer:
1a4d82fc 81
85aaf69f 82```rust
1a4d82fc
JJ
83fn add_one(x: i32) -> i32 {
84 x + 1
85}
86```
87
88Rust functions return exactly one value, and you declare the type after an
9346a6ac
AL
89‘arrow’, which is a dash (`-`) followed by a greater-than sign (`>`). The last
90line of a function determines what it returns. You’ll note the lack of a
91semicolon here. If we added it in:
1a4d82fc 92
9346a6ac 93```rust,ignore
1a4d82fc
JJ
94fn add_one(x: i32) -> i32 {
95 x + 1;
96}
97```
98
99We would get an error:
100
101```text
102error: not all control paths return a value
103fn add_one(x: i32) -> i32 {
104 x + 1;
105}
106
107help: consider removing this semicolon:
108 x + 1;
109 ^
110```
111
9346a6ac
AL
112This reveals two interesting things about Rust: it is an expression-based
113language, and semicolons are different from semicolons in other ‘curly brace
114and semicolon’-based languages. These two things are related.
1a4d82fc 115
9346a6ac 116## Expressions vs. Statements
1a4d82fc 117
9346a6ac
AL
118Rust is primarily an expression-based language. There are only two kinds of
119statements, and everything else is an expression.
1a4d82fc 120
9346a6ac
AL
121So what's the difference? Expressions return a value, and statements do not.
122That’s why we end up with ‘not all control paths return a value’ here: the
123statement `x + 1;` doesn’t return a value. There are two kinds of statements in
124Rust: ‘declaration statements’ and ‘expression statements’. Everything else is
125an expression. Let’s talk about declaration statements first.
126
9cc50fc6 127In some languages, variable bindings can be written as expressions, not
9346a6ac
AL
128statements. Like Ruby:
129
130```ruby
131x = y = 5
132```
133
134In Rust, however, using `let` to introduce a binding is _not_ an expression. The
135following will produce a compile-time error:
136
137```ignore
138let x = (let y = 5); // expected identifier, found keyword `let`
139```
140
141The compiler is telling us here that it was expecting to see the beginning of
142an expression, and a `let` can only begin a statement, not an expression.
143
144Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
145expression, although its value is not particularly useful. Unlike other
146languages where an assignment evaluates to the assigned value (e.g. `5` in the
62682a34 147previous example), in Rust the value of an assignment is an empty tuple `()`
9cc50fc6 148because the assigned value can have [only one owner](ownership.html), and any
62682a34 149other returned value would be too surprising:
9346a6ac 150
62682a34 151```rust
9346a6ac
AL
152let mut y = 5;
153
154let x = (y = 6); // x has the value `()`, not `6`
155```
156
157The second kind of statement in Rust is the *expression statement*. Its
158purpose is to turn any expression into a statement. In practical terms, Rust's
159grammar expects statements to follow other statements. This means that you use
160semicolons to separate expressions from each other. This means that Rust
161looks a lot like most other languages that require you to use semicolons
162at the end of every line, and you will see semicolons at the end of almost
163every line of Rust code you see.
1a4d82fc 164
9346a6ac
AL
165What is this exception that makes us say "almost"? You saw it already, in this
166code:
167
168```rust
169fn add_one(x: i32) -> i32 {
1a4d82fc
JJ
170 x + 1
171}
172```
173
9346a6ac
AL
174Our function claims to return an `i32`, but with a semicolon, it would return
175`()` instead. Rust realizes this probably isn’t what we want, and suggests
176removing the semicolon in the error we saw before.
177
178## Early returns
179
180But what about early returns? Rust does have a keyword for that, `return`:
1a4d82fc 181
85aaf69f 182```rust
1a4d82fc 183fn foo(x: i32) -> i32 {
9346a6ac 184 return x;
1a4d82fc 185
9346a6ac
AL
186 // we never run this code!
187 x + 1
1a4d82fc
JJ
188}
189```
190
9346a6ac
AL
191Using a `return` as the last line of a function works, but is considered poor
192style:
85aaf69f
SL
193
194```rust
195fn foo(x: i32) -> i32 {
9346a6ac 196 return x + 1;
85aaf69f
SL
197}
198```
199
9346a6ac
AL
200The previous definition without `return` may look a bit strange if you haven’t
201worked in an expression-based language before, but it becomes intuitive over
202time.
85aaf69f
SL
203
204## Diverging functions
205
9346a6ac 206Rust has some special syntax for ‘diverging functions’, which are functions that
85aaf69f
SL
207do not return:
208
62682a34 209```rust
85aaf69f
SL
210fn diverges() -> ! {
211 panic!("This function never returns!");
212}
213```
214
9346a6ac 215`panic!` is a macro, similar to `println!()` that we’ve already seen. Unlike
85aaf69f 216`println!()`, `panic!()` causes the current thread of execution to crash with
e9174d1e
SL
217the given message. Because this function will cause a crash, it will never
218return, and so it has the type ‘`!`’, which is read ‘diverges’.
85aaf69f 219
e9174d1e
SL
220If you add a main function that calls `diverges()` and run it, you’ll get
221some output that looks like this:
222
223```text
224thread ‘<main>’ panicked at ‘This function never returns!’, hello.rs:2
225```
226
227If you want more information, you can get a backtrace by setting the
228`RUST_BACKTRACE` environment variable:
229
230```text
231$ RUST_BACKTRACE=1 ./diverges
232thread '<main>' panicked at 'This function never returns!', hello.rs:2
233stack backtrace:
234 1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
235 2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
236 3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw
237 4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650
238 5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa
239 6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa
240 7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231
241 8: 0x7f402773d1d8 - __rust_try
242 9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w
243 10: 0x7f4027738a19 - main
244 11: 0x7f402694ab44 - __libc_start_main
245 12: 0x7f40277386c8 - <unknown>
246 13: 0x0 - <unknown>
247```
248
54a0048b
SL
249If you need to override an already set `RUST_BACKTRACE`,
250in cases when you cannot just unset the variable,
251then set it to `0` to avoid getting a backtrace.
252Any other value(even no value at all) turns on backtrace.
253
254```text
255$ export RUST_BACKTRACE=1
256...
257$ RUST_BACKTRACE=0 ./diverges
258thread '<main>' panicked at 'This function never returns!', hello.rs:2
259note: Run with `RUST_BACKTRACE=1` for a backtrace.
260```
261
e9174d1e
SL
262`RUST_BACKTRACE` also works with Cargo’s `run` command:
263
264```text
265$ RUST_BACKTRACE=1 cargo run
266 Running `target/debug/diverges`
267thread '<main>' panicked at 'This function never returns!', hello.rs:2
268stack backtrace:
269 1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
270 2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
271 3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw
272 4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650
273 5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa
274 6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa
275 7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231
276 8: 0x7f402773d1d8 - __rust_try
277 9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w
278 10: 0x7f4027738a19 - main
279 11: 0x7f402694ab44 - __libc_start_main
280 12: 0x7f40277386c8 - <unknown>
281 13: 0x0 - <unknown>
282```
283
284A diverging function can be used as any type:
85aaf69f 285
c34b1796 286```should_panic
85aaf69f
SL
287# fn diverges() -> ! {
288# panic!("This function never returns!");
289# }
85aaf69f
SL
290let x: i32 = diverges();
291let x: String = diverges();
292```
e9174d1e
SL
293
294## Function pointers
295
296We can also create variable bindings which point to functions:
297
298```rust
299let f: fn(i32) -> i32;
300```
301
302`f` is a variable binding which points to a function that takes an `i32` as
303an argument and returns an `i32`. For example:
304
305```rust
306fn plus_one(i: i32) -> i32 {
307 i + 1
308}
309
310// without type inference
311let f: fn(i32) -> i32 = plus_one;
312
313// with type inference
314let f = plus_one;
315```
316
317We can then use `f` to call the function:
318
319```rust
320# fn plus_one(i: i32) -> i32 { i + 1 }
321# let f = plus_one;
322let six = f(5);
323```