]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## Functions |
2 | ||
94222f64 | 3 | Functions are prevalent in Rust code. You’ve already seen one of the most |
13cf67c4 XL |
4 | important functions in the language: the `main` function, which is the entry |
5 | point of many programs. You’ve also seen the `fn` keyword, which allows you to | |
6 | declare new functions. | |
7 | ||
8 | Rust code uses *snake case* as the conventional style for function and variable | |
3c0e092e | 9 | names, in which all letters are lowercase and underscores separate words. |
13cf67c4 XL |
10 | Here’s a program that contains an example function definition: |
11 | ||
12 | <span class="filename">Filename: src/main.rs</span> | |
13 | ||
14 | ```rust | |
74b04a01 | 15 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-16-functions/src/main.rs}} |
13cf67c4 XL |
16 | ``` |
17 | ||
3c0e092e XL |
18 | We define a function in Rust by entering `fn` followed by a function name and a |
19 | set of parentheses. The curly brackets tell the compiler where the function | |
20 | body begins and ends. | |
13cf67c4 XL |
21 | |
22 | We can call any function we’ve defined by entering its name followed by a set | |
23 | of parentheses. Because `another_function` is defined in the program, it can be | |
24 | called from inside the `main` function. Note that we defined `another_function` | |
25 | *after* the `main` function in the source code; we could have defined it before | |
26 | as well. Rust doesn’t care where you define your functions, only that they’re | |
04454e1e | 27 | defined somewhere in a scope that can be seen by the caller. |
13cf67c4 XL |
28 | |
29 | Let’s start a new binary project named *functions* to explore functions | |
30 | further. Place the `another_function` example in *src/main.rs* and run it. You | |
31 | should see the following output: | |
32 | ||
f035d41b | 33 | ```console |
74b04a01 | 34 | {{#include ../listings/ch03-common-programming-concepts/no-listing-16-functions/output.txt}} |
13cf67c4 XL |
35 | ``` |
36 | ||
37 | The lines execute in the order in which they appear in the `main` function. | |
2b03887a FG |
38 | First the “Hello, world!” message prints, and then `another_function` is called |
39 | and its message is printed. | |
13cf67c4 | 40 | |
3c0e092e | 41 | ### Parameters |
13cf67c4 | 42 | |
3c0e092e XL |
43 | We can define functions to have *parameters*, which are special variables that |
44 | are part of a function’s signature. When a function has parameters, you can | |
45 | provide it with concrete values for those parameters. Technically, the concrete | |
46 | values are called *arguments*, but in casual conversation, people tend to use | |
47 | the words *parameter* and *argument* interchangeably for either the variables | |
48 | in a function’s definition or the concrete values passed in when you call a | |
49 | function. | |
13cf67c4 | 50 | |
3c0e092e | 51 | In this version of `another_function` we add a parameter: |
13cf67c4 XL |
52 | |
53 | <span class="filename">Filename: src/main.rs</span> | |
54 | ||
55 | ```rust | |
74b04a01 | 56 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-17-functions-with-parameters/src/main.rs}} |
13cf67c4 XL |
57 | ``` |
58 | ||
59 | Try running this program; you should get the following output: | |
60 | ||
f035d41b | 61 | ```console |
74b04a01 | 62 | {{#include ../listings/ch03-common-programming-concepts/no-listing-17-functions-with-parameters/output.txt}} |
13cf67c4 XL |
63 | ``` |
64 | ||
65 | The declaration of `another_function` has one parameter named `x`. The type of | |
3c0e092e | 66 | `x` is specified as `i32`. When we pass `5` in to `another_function`, the |
04454e1e FG |
67 | `println!` macro puts `5` where the pair of curly brackets containing `x` was |
68 | in the format string. | |
13cf67c4 XL |
69 | |
70 | In function signatures, you *must* declare the type of each parameter. This is | |
71 | a deliberate decision in Rust’s design: requiring type annotations in function | |
72 | definitions means the compiler almost never needs you to use them elsewhere in | |
04454e1e FG |
73 | the code to figure out what type you mean. The compiler is also able to give |
74 | more helpful error messages if it knows what types the function expects. | |
13cf67c4 | 75 | |
3c0e092e XL |
76 | When defining multiple parameters, separate the parameter declarations with |
77 | commas, like this: | |
13cf67c4 XL |
78 | |
79 | <span class="filename">Filename: src/main.rs</span> | |
80 | ||
81 | ```rust | |
74b04a01 | 82 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-18-functions-with-multiple-parameters/src/main.rs}} |
13cf67c4 XL |
83 | ``` |
84 | ||
94222f64 XL |
85 | This example creates a function named `print_labeled_measurement` with two |
86 | parameters. The first parameter is named `value` and is an `i32`. The second is | |
87 | named `unit_label` and is type `char`. The function then prints text containing | |
88 | both the `value` and the `unit_label`. | |
13cf67c4 XL |
89 | |
90 | Let’s try running this code. Replace the program currently in your *functions* | |
91 | project’s *src/main.rs* file with the preceding example and run it using `cargo | |
92 | run`: | |
93 | ||
f035d41b | 94 | ```console |
74b04a01 | 95 | {{#include ../listings/ch03-common-programming-concepts/no-listing-18-functions-with-multiple-parameters/output.txt}} |
13cf67c4 XL |
96 | ``` |
97 | ||
94222f64 XL |
98 | Because we called the function with `5` as the value for `value` and `'h'` as |
99 | the value for `unit_label`, the program output contains those values. | |
13cf67c4 | 100 | |
3c0e092e | 101 | ### Statements and Expressions |
13cf67c4 XL |
102 | |
103 | Function bodies are made up of a series of statements optionally ending in an | |
3c0e092e XL |
104 | expression. So far, the functions we’ve covered haven’t included an ending |
105 | expression, but you have seen an expression as part of a statement. Because | |
106 | Rust is an expression-based language, this is an important distinction to | |
107 | understand. Other languages don’t have the same distinctions, so let’s look at | |
108 | what statements and expressions are and how their differences affect the bodies | |
109 | of functions. | |
13cf67c4 | 110 | |
2b03887a FG |
111 | * **Statements** are instructions that perform some action and do not return |
112 | a value. | |
113 | * **Expressions** evaluate to a resultant value. Let’s look at some examples. | |
13cf67c4 | 114 | |
3c0e092e XL |
115 | We’ve actually already used statements and expressions. Creating a variable and |
116 | assigning a value to it with the `let` keyword is a statement. In Listing 3-1, | |
117 | `let y = 6;` is a statement. | |
13cf67c4 XL |
118 | |
119 | <span class="filename">Filename: src/main.rs</span> | |
120 | ||
121 | ```rust | |
74b04a01 | 122 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-01/src/main.rs}} |
13cf67c4 XL |
123 | ``` |
124 | ||
125 | <span class="caption">Listing 3-1: A `main` function declaration containing one statement</span> | |
126 | ||
127 | Function definitions are also statements; the entire preceding example is a | |
128 | statement in itself. | |
129 | ||
130 | Statements do not return values. Therefore, you can’t assign a `let` statement | |
131 | to another variable, as the following code tries to do; you’ll get an error: | |
132 | ||
133 | <span class="filename">Filename: src/main.rs</span> | |
134 | ||
135 | ```rust,ignore,does_not_compile | |
74b04a01 | 136 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/src/main.rs}} |
13cf67c4 XL |
137 | ``` |
138 | ||
139 | When you run this program, the error you’ll get looks like this: | |
f035d41b XL |
140 | |
141 | ```console | |
ba9703b0 | 142 | {{#include ../listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt}} |
13cf67c4 XL |
143 | ``` |
144 | ||
145 | The `let y = 6` statement does not return a value, so there isn’t anything for | |
146 | `x` to bind to. This is different from what happens in other languages, such as | |
147 | C and Ruby, where the assignment returns the value of the assignment. In those | |
148 | languages, you can write `x = y = 6` and have both `x` and `y` have the value | |
149 | `6`; that is not the case in Rust. | |
150 | ||
94222f64 XL |
151 | Expressions evaluate to a value and make up most of the rest of the code that |
152 | you’ll write in Rust. Consider a math operation, such as `5 + 6`, which is an | |
153 | expression that evaluates to the value `11`. Expressions can be part of | |
13cf67c4 XL |
154 | statements: in Listing 3-1, the `6` in the statement `let y = 6;` is an |
155 | expression that evaluates to the value `6`. Calling a function is an | |
3c0e092e XL |
156 | expression. Calling a macro is an expression. A new scope block created with |
157 | curly brackets is an expression, for example: | |
13cf67c4 XL |
158 | |
159 | <span class="filename">Filename: src/main.rs</span> | |
160 | ||
161 | ```rust | |
74b04a01 | 162 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs}} |
13cf67c4 XL |
163 | ``` |
164 | ||
165 | This expression: | |
166 | ||
167 | ```rust,ignore | |
168 | { | |
169 | let x = 3; | |
170 | x + 1 | |
171 | } | |
172 | ``` | |
173 | ||
174 | is a block that, in this case, evaluates to `4`. That value gets bound to `y` | |
3c0e092e | 175 | as part of the `let` statement. Note that the `x + 1` line doesn’t have a |
2b03887a FG |
176 | semicolon at the end, which is unlike most of the lines you’ve seen so far. |
177 | Expressions do not include ending semicolons. If you add a semicolon to the end | |
178 | of an expression, you turn it into a statement, and it will then not return a | |
179 | value. Keep this in mind as you explore function return values and expressions | |
180 | next. | |
13cf67c4 XL |
181 | |
182 | ### Functions with Return Values | |
183 | ||
184 | Functions can return values to the code that calls them. We don’t name return | |
a2a8927a XL |
185 | values, but we must declare their type after an arrow (`->`). In Rust, the |
186 | return value of the function is synonymous with the value of the final | |
187 | expression in the block of the body of a function. You can return early from a | |
188 | function by using the `return` keyword and specifying a value, but most | |
189 | functions return the last expression implicitly. Here’s an example of a | |
190 | function that returns a value: | |
13cf67c4 XL |
191 | |
192 | <span class="filename">Filename: src/main.rs</span> | |
193 | ||
194 | ```rust | |
74b04a01 | 195 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-21-function-return-values/src/main.rs}} |
13cf67c4 XL |
196 | ``` |
197 | ||
198 | There are no function calls, macros, or even `let` statements in the `five` | |
199 | function—just the number `5` by itself. That’s a perfectly valid function in | |
9fa01778 | 200 | Rust. Note that the function’s return type is specified too, as `-> i32`. Try |
13cf67c4 XL |
201 | running this code; the output should look like this: |
202 | ||
f035d41b | 203 | ```console |
74b04a01 | 204 | {{#include ../listings/ch03-common-programming-concepts/no-listing-21-function-return-values/output.txt}} |
13cf67c4 XL |
205 | ``` |
206 | ||
207 | The `5` in `five` is the function’s return value, which is why the return type | |
208 | is `i32`. Let’s examine this in more detail. There are two important bits: | |
209 | first, the line `let x = five();` shows that we’re using the return value of a | |
210 | function to initialize a variable. Because the function `five` returns a `5`, | |
211 | that line is the same as the following: | |
212 | ||
213 | ```rust | |
214 | let x = 5; | |
215 | ``` | |
216 | ||
217 | Second, the `five` function has no parameters and defines the type of the | |
218 | return value, but the body of the function is a lonely `5` with no semicolon | |
219 | because it’s an expression whose value we want to return. | |
220 | ||
221 | Let’s look at another example: | |
222 | ||
223 | <span class="filename">Filename: src/main.rs</span> | |
224 | ||
225 | ```rust | |
74b04a01 | 226 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-22-function-parameter-and-return/src/main.rs}} |
13cf67c4 XL |
227 | ``` |
228 | ||
229 | Running this code will print `The value of x is: 6`. But if we place a | |
230 | semicolon at the end of the line containing `x + 1`, changing it from an | |
2b03887a | 231 | expression to a statement, we’ll get an error: |
13cf67c4 XL |
232 | |
233 | <span class="filename">Filename: src/main.rs</span> | |
234 | ||
235 | ```rust,ignore,does_not_compile | |
74b04a01 | 236 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/src/main.rs}} |
13cf67c4 XL |
237 | ``` |
238 | ||
239 | Compiling this code produces an error, as follows: | |
240 | ||
f035d41b | 241 | ```console |
74b04a01 | 242 | {{#include ../listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt}} |
13cf67c4 XL |
243 | ``` |
244 | ||
2b03887a | 245 | The main error message, `mismatched types`, reveals the core issue with this |
13cf67c4 XL |
246 | code. The definition of the function `plus_one` says that it will return an |
247 | `i32`, but statements don’t evaluate to a value, which is expressed by `()`, | |
94222f64 | 248 | the unit type. Therefore, nothing is returned, which contradicts the function |
13cf67c4 XL |
249 | definition and results in an error. In this output, Rust provides a message to |
250 | possibly help rectify this issue: it suggests removing the semicolon, which | |
251 | would fix the error. |