]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | % Functions |
2 | ||
9346a6ac | 3 | Every Rust program has at least one function, the `main` function: |
1a4d82fc | 4 | |
85aaf69f | 5 | ```rust |
1a4d82fc JJ |
6 | fn main() { |
7 | } | |
8 | ``` | |
9 | ||
10 | This 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 | 12 | this function takes no arguments, and then some curly braces to indicate the |
9346a6ac | 13 | body. Here’s a function named `foo`: |
1a4d82fc | 14 | |
85aaf69f | 15 | ```rust |
1a4d82fc JJ |
16 | fn foo() { |
17 | } | |
18 | ``` | |
19 | ||
9346a6ac | 20 | So, what about taking arguments? Here’s a function that prints a number: |
1a4d82fc | 21 | |
85aaf69f | 22 | ```rust |
1a4d82fc JJ |
23 | fn print_number(x: i32) { |
24 | println!("x is: {}", x); | |
25 | } | |
26 | ``` | |
27 | ||
9346a6ac | 28 | Here’s a complete program that uses `print_number`: |
1a4d82fc | 29 | |
85aaf69f | 30 | ```rust |
1a4d82fc JJ |
31 | fn main() { |
32 | print_number(5); | |
33 | } | |
34 | ||
35 | fn print_number(x: i32) { | |
36 | println!("x is: {}", x); | |
37 | } | |
38 | ``` | |
39 | ||
40 | As you can see, function arguments work very similar to `let` declarations: | |
41 | you add a type to the argument name, after a colon. | |
42 | ||
9346a6ac | 43 | Here’s a complete program that adds two numbers together and prints them: |
1a4d82fc | 44 | |
85aaf69f | 45 | ```rust |
1a4d82fc JJ |
46 | fn main() { |
47 | print_sum(5, 6); | |
48 | } | |
49 | ||
50 | fn print_sum(x: i32, y: i32) { | |
51 | println!("sum is: {}", x + y); | |
52 | } | |
53 | ``` | |
54 | ||
55 | You separate arguments with a comma, both when you call the function, as well | |
56 | as when you declare it. | |
57 | ||
58 | Unlike `let`, you _must_ declare the types of function arguments. This does | |
59 | not work: | |
60 | ||
9346a6ac | 61 | ```rust,ignore |
85aaf69f SL |
62 | fn print_sum(x, y) { |
63 | println!("sum is: {}", x + y); | |
1a4d82fc JJ |
64 | } |
65 | ``` | |
66 | ||
67 | You get this error: | |
68 | ||
69 | ```text | |
9346a6ac | 70 | expected one of `!`, `:`, or `@`, found `)` |
7453a54e | 71 | fn print_sum(x, y) { |
1a4d82fc JJ |
72 | ``` |
73 | ||
74 | This is a deliberate design decision. While full-program inference is possible, | |
75 | languages which have it, like Haskell, often suggest that documenting your | |
76 | types explicitly is a best-practice. We agree that forcing functions to declare | |
77 | types while allowing for inference inside of function bodies is a wonderful | |
78 | sweet spot between full inference and no inference. | |
79 | ||
9346a6ac | 80 | What about returning a value? Here’s a function that adds one to an integer: |
1a4d82fc | 81 | |
85aaf69f | 82 | ```rust |
1a4d82fc JJ |
83 | fn add_one(x: i32) -> i32 { |
84 | x + 1 | |
85 | } | |
86 | ``` | |
87 | ||
88 | Rust 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 |
90 | line of a function determines what it returns. You’ll note the lack of a | |
91 | semicolon here. If we added it in: | |
1a4d82fc | 92 | |
9346a6ac | 93 | ```rust,ignore |
1a4d82fc JJ |
94 | fn add_one(x: i32) -> i32 { |
95 | x + 1; | |
96 | } | |
97 | ``` | |
98 | ||
99 | We would get an error: | |
100 | ||
101 | ```text | |
102 | error: not all control paths return a value | |
103 | fn add_one(x: i32) -> i32 { | |
104 | x + 1; | |
105 | } | |
106 | ||
107 | help: consider removing this semicolon: | |
108 | x + 1; | |
109 | ^ | |
110 | ``` | |
111 | ||
9346a6ac AL |
112 | This reveals two interesting things about Rust: it is an expression-based |
113 | language, and semicolons are different from semicolons in other ‘curly brace | |
114 | and semicolon’-based languages. These two things are related. | |
1a4d82fc | 115 | |
9346a6ac | 116 | ## Expressions vs. Statements |
1a4d82fc | 117 | |
9346a6ac AL |
118 | Rust is primarily an expression-based language. There are only two kinds of |
119 | statements, and everything else is an expression. | |
1a4d82fc | 120 | |
9346a6ac AL |
121 | So what's the difference? Expressions return a value, and statements do not. |
122 | That’s why we end up with ‘not all control paths return a value’ here: the | |
123 | statement `x + 1;` doesn’t return a value. There are two kinds of statements in | |
124 | Rust: ‘declaration statements’ and ‘expression statements’. Everything else is | |
125 | an expression. Let’s talk about declaration statements first. | |
126 | ||
9cc50fc6 | 127 | In some languages, variable bindings can be written as expressions, not |
9346a6ac AL |
128 | statements. Like Ruby: |
129 | ||
130 | ```ruby | |
131 | x = y = 5 | |
132 | ``` | |
133 | ||
134 | In Rust, however, using `let` to introduce a binding is _not_ an expression. The | |
135 | following will produce a compile-time error: | |
136 | ||
137 | ```ignore | |
138 | let x = (let y = 5); // expected identifier, found keyword `let` | |
139 | ``` | |
140 | ||
141 | The compiler is telling us here that it was expecting to see the beginning of | |
142 | an expression, and a `let` can only begin a statement, not an expression. | |
143 | ||
144 | Note that assigning to an already-bound variable (e.g. `y = 5`) is still an | |
145 | expression, although its value is not particularly useful. Unlike other | |
146 | languages where an assignment evaluates to the assigned value (e.g. `5` in the | |
62682a34 | 147 | previous example), in Rust the value of an assignment is an empty tuple `()` |
9cc50fc6 | 148 | because the assigned value can have [only one owner](ownership.html), and any |
62682a34 | 149 | other returned value would be too surprising: |
9346a6ac | 150 | |
62682a34 | 151 | ```rust |
9346a6ac AL |
152 | let mut y = 5; |
153 | ||
154 | let x = (y = 6); // x has the value `()`, not `6` | |
155 | ``` | |
156 | ||
157 | The second kind of statement in Rust is the *expression statement*. Its | |
158 | purpose is to turn any expression into a statement. In practical terms, Rust's | |
159 | grammar expects statements to follow other statements. This means that you use | |
160 | semicolons to separate expressions from each other. This means that Rust | |
161 | looks a lot like most other languages that require you to use semicolons | |
162 | at the end of every line, and you will see semicolons at the end of almost | |
163 | every line of Rust code you see. | |
1a4d82fc | 164 | |
9346a6ac AL |
165 | What is this exception that makes us say "almost"? You saw it already, in this |
166 | code: | |
167 | ||
168 | ```rust | |
169 | fn add_one(x: i32) -> i32 { | |
1a4d82fc JJ |
170 | x + 1 |
171 | } | |
172 | ``` | |
173 | ||
9346a6ac AL |
174 | Our 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 | |
176 | removing the semicolon in the error we saw before. | |
177 | ||
178 | ## Early returns | |
179 | ||
180 | But what about early returns? Rust does have a keyword for that, `return`: | |
1a4d82fc | 181 | |
85aaf69f | 182 | ```rust |
1a4d82fc | 183 | fn 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 |
191 | Using a `return` as the last line of a function works, but is considered poor |
192 | style: | |
85aaf69f SL |
193 | |
194 | ```rust | |
195 | fn foo(x: i32) -> i32 { | |
9346a6ac | 196 | return x + 1; |
85aaf69f SL |
197 | } |
198 | ``` | |
199 | ||
9346a6ac AL |
200 | The previous definition without `return` may look a bit strange if you haven’t |
201 | worked in an expression-based language before, but it becomes intuitive over | |
202 | time. | |
85aaf69f SL |
203 | |
204 | ## Diverging functions | |
205 | ||
9346a6ac | 206 | Rust has some special syntax for ‘diverging functions’, which are functions that |
85aaf69f SL |
207 | do not return: |
208 | ||
62682a34 | 209 | ```rust |
85aaf69f SL |
210 | fn 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 |
217 | the given message. Because this function will cause a crash, it will never |
218 | return, and so it has the type ‘`!`’, which is read ‘diverges’. | |
85aaf69f | 219 | |
e9174d1e SL |
220 | If you add a main function that calls `diverges()` and run it, you’ll get |
221 | some output that looks like this: | |
222 | ||
223 | ```text | |
224 | thread ‘<main>’ panicked at ‘This function never returns!’, hello.rs:2 | |
225 | ``` | |
226 | ||
227 | If 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 | |
232 | thread '<main>' panicked at 'This function never returns!', hello.rs:2 | |
233 | stack 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 |
249 | If you need to override an already set `RUST_BACKTRACE`, |
250 | in cases when you cannot just unset the variable, | |
251 | then set it to `0` to avoid getting a backtrace. | |
252 | Any other value(even no value at all) turns on backtrace. | |
253 | ||
254 | ```text | |
255 | $ export RUST_BACKTRACE=1 | |
256 | ... | |
257 | $ RUST_BACKTRACE=0 ./diverges | |
258 | thread '<main>' panicked at 'This function never returns!', hello.rs:2 | |
259 | note: 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` | |
267 | thread '<main>' panicked at 'This function never returns!', hello.rs:2 | |
268 | stack 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 | ||
284 | A 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 |
290 | let x: i32 = diverges(); |
291 | let x: String = diverges(); | |
292 | ``` | |
e9174d1e SL |
293 | |
294 | ## Function pointers | |
295 | ||
296 | We can also create variable bindings which point to functions: | |
297 | ||
298 | ```rust | |
299 | let f: fn(i32) -> i32; | |
300 | ``` | |
301 | ||
302 | `f` is a variable binding which points to a function that takes an `i32` as | |
303 | an argument and returns an `i32`. For example: | |
304 | ||
305 | ```rust | |
306 | fn plus_one(i: i32) -> i32 { | |
307 | i + 1 | |
308 | } | |
309 | ||
310 | // without type inference | |
311 | let f: fn(i32) -> i32 = plus_one; | |
312 | ||
313 | // with type inference | |
314 | let f = plus_one; | |
315 | ``` | |
316 | ||
317 | We 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; | |
322 | let six = f(5); | |
323 | ``` |